栈的顺序存储
栈(Stack)是只允许在一端进行插入和删除的线性表
n个不同元素进栈,出栈元素不同排列的个数[1/(n+1)]C2n,n
定义
#define MaxSize 10//栈中最大元素个数
typedef struct{
ElemType data[MaxSize];//栈中元素
int top;//栈顶指针
}SqStack;
- 栈顶指针:
S.top
,指向当前栈顶元素的位置 - 栈顶元素:
S.data[S.top]
- 进栈:栈不满,栈顶指针加1,再送元素到栈顶元素
- 出栈:栈非空,先取栈顶元素,再将栈顶指针减1
- 栈空:
S.top=-1
- 栈满:
S.top==MaxSize-1
- 栈长:
S.top+1
初始化
void InitStack(SqStack &S){
S.top=-1;//初始化栈顶指针
}
进栈
bool Push(SqStack &S,ElemType x){
if(S.top==MaxSize-1){
return false;
}
S.data[++S.top]=x;//指针先加1,元素再入栈
return true;
}
出栈
bool Pop(SqStack &s,ElemType &x){
if(S.top==-1){
return false;
}
x=S.data[S.top--];//元素先出,指针减1
return true;
}
共享栈
两个栈的栈底分别设置在一个数组的两端,栈顶向中间延伸
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int top[2];//0,1号栈顶指针
}ShStack;
//初始化栈
void InitStack(ShStack &S){
S.top[0]=-1;
S.top[1]=MaxSize;
}
- 栈空:
top0=-1
0号栈空;top1=MaxSize
1号栈空 - 栈满:
top1-top0=1
- 0号进栈,
top0
先加1再赋值 - 1号进栈,
top1
先减1在赋值
入栈
//i为栈号,i=0表示左边的栈,i=1表示右边的栈,x是入栈元素
int Push(ShStack &S,int i,ElemType x){
if(i<0||i>1){
printf("栈号输入不对");
exit(0);
}
if(S.top[1]-S.top[0]==1){
printf("栈满\n");
return 0;
}
switch(i){
case 0: S.data[++S.top[0]]=x;
return 1;
break;
case 1: S.data[--S.top[1]]=x;
return 1;
}
}
出栈
//出栈,i=0表示左边的栈,i=1表示右边的栈
ElemType pop(ShStack &S,int i){
if(i<0||i>1){
printf("栈号输入错误\n");
exit(0);
}
switch(i){
case 0:
if(S.top[0]==-1){
printf("栈空\n");
return -1;
}
else{
return S.data[S.top[0]--];
}
case 1:
if(S.top[1]==MaxSize){
printf("栈空\n");
return -1;
}
else{
return S.data[S.top[1]++];
}
}
}
栈的链式存储
链栈(不存再栈满上溢,所有操作都是在链表表头进行的)
//定义
typedef struct LinkNode{
ElemType data;//数据域
struct LinkNode *next;//指针域
}*LiStack;
- 入栈就是单链表的头插法
- 出栈就是单链表删除头结点
栈的应用
括号匹配
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 StackEmpty(S);
}
表达式求值
递归
递归调用:将原始问题转换为属性相同,规模较小的问题
函数调用,系统为每一层的返回点,局部变量,传入实参等开辟了递归工作栈来进行数据存储(递归次数过多容易栈溢出)