栈
定义:只允许在一端进行插入或删除操作的线性表。
栈顶:线性表允许进行插入删除的那一端。
栈底:固定的,不允许进行插入删除的另一端。
空栈:不含任何元素的空表。
特性:后进先出。(LIFO)
数学性质:n个不同的元素进栈,出栈元素不同排列的个数为(n+1)<sup>-1</sup>C<sup>n</sup><sub>2n</sub>。
顺序栈
栈顶指针:S.data[S.top]
进栈:栈不满时,栈顶指针先加1,再送值到栈顶元素。
出栈:栈非空时,先取栈顶元素,再将栈顶指针减1.
栈空:S.top==-1 栈满:S.top==MAXSize-1 栈长:S.top+1
共享栈
定义:利用栈底位置相对不变的特性,可让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈底向共享空间的中间延申。
两个栈的栈顶指针都指向栈顶元素,top0=-1时,0号栈为空,top1=MAXSize时1号栈为空。仅当两个栈顶指针相邻(top1-top0=1)时,栈满。
0号栈进栈时,top0先加1再赋值,1号栈进栈时top1先减1再赋值;出栈则相反。
特点:为了更有效的利用存储空间,两个栈的空间相互调节,只有在整个存储空间被占满时才发生上溢。
链栈
优点:便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。便于结点的插入和删除。
应用
-
括号匹配:遇到左括号进栈,遇到右括号出栈。算法结束,栈为空,否则括号序列不匹配。
-
中缀表达式转后缀表达式:中缀表达式不仅依赖运算符的优先级,还有处理括号。后缀表达式已经考虑了运算符的优先级,没有括号,只有操作数和运算符。
中缀表达式转后缀表达式步骤:
1 根据操作符<op>的优先级来进行栈的变化
2 从左向右扫描中缀表达式
2.1 遇到数字时加入后缀表达式
2.2 遇到运算符时,根据优先级判断
2.2.1 遇到"("入栈
2.2.2 遇到")"则依次将栈中的运算符加入后缀表达式,直到出现"(",从栈中删除"("
2.2.3 除括号外的其他运算符,当其优先级高于'('外的栈顶运算符,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和相等的运算符,直到一个比它优先级低的或遇到一个左括号为止。
3. 扫描结束时,栈中的所有运算符依次出栈加入后缀表达式。
- 表达式求值:使用后缀表达式
1. 遇到操作数则进栈
2. 遇到操作符,栈中前两个元素退栈,进行计数后的结果入栈
3. 扫描处理完成后,栈顶存放的就是最后的计算结果
- 在递归中的应用
优点:代码简单,容易理解。
缺点:递归次数过多容易造成栈溢出,递归调用过程包含很多重复计算,效率不高
- 进制转换
- 迷宫求解
大题
- 判断一个序列是否是合法序列(初态和终态均为空)。
int Judge(char A[]){
int i=0;
int j=k=0;
while(A[i]!='\0'){
switch(A[i]){
case 'I': j++; break;
case 'O': k++;
if(k>j){
printf('序列非法\n');
exit(0);
}
}
i++;
}
if(j!=k){
printf('序列非法\n');
return false;
}else{
printf('序列合法\n');
return true;
}
}
- 判断链表的全部n个字符是否中心对称
//思路:先将一半元素进栈。n为偶数,比较前一半和后一半;n为奇数,指针跳到下一个字符开始比较。
int dc(LinkList L, int n){
int i;
char s[n/2];
p=L->next;
for(i=0;i<n/2;i++){
s[i]=p->data;
p=p->next;
}
i--;
if(n%2==1)
p=p->next;
while(p!=NULL&&s[i]==p->data){
i--;
p=p->next;
}
if(i==-1)
return 1;
else
return 0;
}
- 有两个栈s1、s2都采用顺序栈方式,并共享一个存储区[0,…,maxsize-1],采用栈顶相向,迎面增长的存储方式,设计s1、s2有关入栈和出栈的操作算法。
//入栈
int push(int i,elemty x){
//i为栈号,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.stack[++s.top[0]]=x; return 1; break;
case 1:s.stack[--s.top[1]]=x; return 1;
}
}
//出栈
elemtp pop(int i){
if(i<0||i>1){
printf("栈号输入错误");
exit(0);
}
switch(i){
case 0:
if(s.top[0]==-1){
printf("栈空\n");
return -1;
}
else
return s.stack[s.top[0]]--;
case 1:
if(s.top[1]==maxsize){
printf("栈空\n");
return -1;
}
else
return s.stack[s.top[1]]++;
}
}
- 假设一个算术表达式中包含圆括号、方括号和花括号3中类型的括号,编写一个算法来判别表达式中的括号是否配对,以字符“\n”作为表达式的结束符。
bool BracketsCheck(char *str){
InitStack(S);
int i=0;
while(str[i]!='\n'){
switch(str[i]){
case '(': Push(S,'('); break;
case '[': Push(S,'['); break;
case '{': Push(S,'{'); break;
case ')': Pop(S,e);
if(e!='(') return false;
break;
case ']': Pop(S,e);
if(e!='[') return false;
break;
case '}': Pop(S,e);
if(e!='{') return false;
break;
default:
break;
}
i++;
}
if(!IsEmpty(S)){
printf("括号不匹配\n");
return false;
}else{
printf("括号匹配");
return true;
}
}