栈
括号匹配
- 依次扫描所有字符,遇到左括号入栈,遇到右括号则弹出栈顶元素检查是否匹配
- 匹配失败情况:左括号单身、右括号单身、左右括号不匹配
#define MaxSize 10
typedef struct{
char data[MaxSize];
int top;
}SqStack;
//初始化栈
void InitStack(SqStack &S)
//判断栈是否为空
bool StackEmpty(SqStack S)
//新元素入栈
bool Push(SqStack &S,char x)
//栈顶元素出栈,用x返回
bool Pop(SqStack &S,char &x)
bool bracketChaeck(char str[],int length){
SqStack S;
InitStack(S); //初始化一个栈
for(int i = 0;i < length;i++){
if(str[i] == '(' || str[i] == '[' || str[i] == '{'){
Push(S,str[i]); //扫描到左括号,入栈
}else{
if(StackEmpty(S)) //扫描到右括号,且当前栈空
return false; //匹配失败
char tomElem;
Pop(S,topElem); //栈顶元素出栈
if(str[i] == ')' && topElem != '(')
return false;
if(str[i] == ']' && topElem != '[')
return false;
if(str[i] == '}' && topElem != '{')
return false;
}
}
return StackEmpty(S); //检索完全部括号后,栈空说明匹配成功
}
表达式求值
操作数、运算符、界限符
中缀表达式
中缀转后缀--手算方法:
- 确定中缀表达式中各个运算符的运算顺序(运算顺序不唯一,对应后缀表达式也不唯一)
- 选择下一个运算符,按照【左、右、运算符】的方式组合成一个新的操作数
- 如果还有运算符没被处理,继续上一步
左优先
机算
初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。
从左到右处理各个元素,直到末尾。可能遇到三种情况:
- 遇到操作数。直接加入后缀表达式
- 遇到界限符。遇到'('直接入栈;遇到')'则依次弹出栈内运算符并加入后缀表达式,直到弹出'('为止。'('不加入后缀表达式
- 遇到运算符。依次弹出栈中优先级高于或等于当前运算符的所有运算符,并加入后缀表达式,若遇到'('或栈空则停止。之后再把当前运算符入栈
按上述处理完所有字符后,栈中剩余运算符依次弹出,并加入后缀表达式
用栈实现中缀表达式的计算
利用中缀转后缀以及后缀计算的栈实现算法结合
- 初始化两个栈,操作数栈和运算符栈
- 若扫描到操作数,压入操作数栈
- 若扫描到运算符或界限符,则按照"中缀转后缀"相同的逻辑压入运算符栈(期间弹出运算符,需要再弹出两个操作数栈的栈顶元素执行运算,之后压入操作数栈)
后缀表达式(逆波兰表达式)
中缀表达式转后缀表达式;后缀表达式求值
用栈实现后缀表达式的计算:
- 从左往右扫描下一个元素,直到处理完所有元素
- 若扫描到操作数则压入栈,并回到1;否则执行3
- 若扫描到运算符,则弹出两个栈顶元素("右操作数"先出栈),执行相应运算,运算结果压回栈顶,回到1
- 结果:若表达式合法,则最后栈中只会留下一个元素为最终结果
前缀表达式(波兰表达式)
中缀表达式转前缀表达式;前缀表达式求值
中缀转前缀
- 确定中缀表达式中各个运算符的运算顺序
- 选择下一个运算符,按照【运算符、左、右】的方式组合成一个新的操作数
- 如果还有运算符没被处理,继续上一步
右优先
用栈实现前缀表达式计算
- 从右往左扫描下一个元素,直到处理完所有元素
- 若扫描到操作数则压入栈,并回到1;否则执行3
- 若扫描到运算符,则弹出两个栈顶元素("左操作数"先出栈),执行相应运算,运算结果压回栈顶,回到1
递归
函数调用的特点:最后被调用的函数最先执行结束(LIFO)
函数调用时,需要用一个栈存储:调用返回地址 实参 局部变量
递归调用时,函数调用栈可成为递归工作栈每进入一层递归,就将递归调用所需信息压入栈顶
缺点:效率低,太多层递归可能会导致栈溢出;可能包含很多重复计算
队列
树的层次遍历
图的广度优先遍历
在操作系统中的应用
先来先服务:队列辅助完成FCFS