栈
1.栈的定义
简单的理解,栈是只允许在一端进行插入或者操作的线性表
2.栈的基本操作
- InitStack(&S):初始化栈。构造一个空栈,分配内存空间。
- DestroyStack(&L):销毁栈。销毁并释放栈S所占用的内存空间
- Push(&S,x):进栈,若栈S未满,则将x加入栈中成为新的栈顶
- Pop(&S,&x):出栈,若栈S非空,则弹出栈顶元素,并用x返回
- GetTop(S,&x):读栈顶元素,用x返回栈顶元素
3.顺序栈
1 2 3 4 5 6
| #define MaxSize 10 typrdef struct { ElemType data[MaxSize]; int top; }SqStack;
|
1 2 3 4
| voif InitStack(SqStack &s) { s.top=-1; }
|
1 2 3 4 5 6 7 8
| bool Push(SqStack &S,ElemType x) { if(S.top==MaxSize-1) return false; S.top = S.top + 1; S.data[S.top]=x; return true; }
|
1 2 3 4 5 6 7 8
| bool Pop(SqStack &S,ElemType &x) { if(S.top==-1) return false; x=S.data[S.top]; S.top = S.top-1; return true; }
|
4.链栈
使用链式存储方式实现的栈,实现头插和后删的单链表
1 2 3 4 5
| typedef struct Linknode { ElemType data; struct Linknode *next; }*LiStack;
|
5.栈的应用——括号匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| bool bracketCheck(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 topElem; Pop(S,topElem); if(str[i]==')'&&topElem!='(') return false; if(str[i]==']'&&topElem!='[') return false; if(str[i]=='}'&&topElem!='{') return false; } } return false; }
|
用栈实现括号匹配,依次扫描所有字符,遇到左括号入栈,遇到有括号则弹出栈顶元素检查是否匹配,匹配失败的情况只有三种:左括号单一,右括号单一,左右括号不匹配。
6.栈的应用——表达式求值的应用
后缀表达式采用”左优先原则”:只要左边的运算符能先计算,就优先计算左边的。
前缀表达式采用“右优先原则”:只要右边的运算符能先计算,就优先计算右边的。
用栈实现中中缀表达式的计算:首先初始化两个栈,操作数栈和运算符栈,若扫描到操作数,压入操作数栈,若扫描到运算符或界限符,则按照“中缀转后缀 ”相同的逻辑压入运算符栈(期间也会弹出运算符,每当弹出一个运算符时,就需要再弹出两个操作数栈的栈顶元素并执行相应运算,运算结果再压回操作数栈中)
8.栈的应用——递归的应用
函数调用的特点是最后被调用的函数最先执行结束,函数调用时,需要用一个栈存储,包括调用返回地址、实参、局部变量。
1 2 3 4 5 6 7 8 9 10 11 12 13
| int factorial(int n) { if (n==0||n==1) return 1; else return n*factorial(n-1); }
int main() { int x=factorial(10); printf("计算完成"); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int Fib(int n) { if (n==0) return 0; else if(n==1) return 1; else return Fib(n-1)+Fib(n-2) }
int main() { int x=Fib(4); printf("计算完成"); }
|
太多层递归可能会导致栈溢出,或者包含很多重复的计算,浪费大量的时间时间。