对stack概念的理解与应用
stack,中文翻译做“栈”,特点就是先进后出,后进先出。
像盖房子一样,新的数据总是被放在上层,若要取数据,就像拆房子,不要太暴力的方式,就要从顶层一层层往下拆。
stack有几种操作,push——进栈,pop——出栈,isempty——检查是否为空栈,top——栈顶元素位置。
1 #include<stdio.h> 2 #include<malloc.h> 3 #define DataType int 4 #define MAXSIZE 1024 5 typedef struct 6 { 7 DataType data[MAXSIZE]; 8 int top; 9 }SeqStack; 10 SeqStack *Init_SeqStack()//栈初始化 11 { 12 SeqStack *s; 13 s=(SeqStack *)malloc(sizeof(SeqStack));//申请空间 14 if(!s) 15 { 16 printf("空间不足\n"); 17 return NULL; 18 } 19 else 20 { 21 s->top=-1; 22 return s; 23 } 24 } 25 int Empty_SeqStack(SeqStack *s)//判栈空 26 { 27 if(s->top==-1) return 1; 28 else return 0; 29 } 30 int Push_SeqStack(SeqStack *s,DataType x)//入栈 31 { 32 if(s->top==MAXSIZE-1) return 0;//栈满不能入栈 33 else 34 { 35 s->top++;//栈顶+1 36 s->data[s->top]=x;//将元素放入data数组中 37 return 1; 38 } 39 } 40 int Pop_SeqStack(SeqStack *s,DataType *x)//出栈 41 { 42 if(Empty_SeqStack(s)) return 0;//栈空不能出栈 43 else 44 { 45 *x=s->data[s->top]; 46 s->top--;//栈顶-1 47 return 1; 48 }//栈顶元素存入*x,返回 49 } 50 DataType Top_SeqStack(SeqStack *s)//取栈顶元素 51 { 52 if(Empty_SeqStack(s)) return 0;//栈空 53 else return s->data[s->top]; 54 } 55 int Print_SeqStack(SeqStack *s)//打印栈中所有元素 56 { 57 int i; 58 printf("当前栈中的元素:\n"); 59 for(i=s->top;i>=0;i--) printf("%3d",s->data[i]); 60 printf("\n"); 61 return 0; 62 } 63 int main() 64 { 65 SeqStack *L; 66 int n,num,m; 67 int i; 68 L=Init_SeqStack(); 69 printf("初始化完成\n"); 70 printf("栈空:%d\n",Empty_SeqStack(L)); 71 printf("请输入入栈元素个数:\n"); 72 scanf("%d",&n); 73 printf("请输入要入栈的%d个元素:\n",n); 74 for(i=0;i<n;i++) 75 { 76 scanf("%d",&num); 77 Push_SeqStack(L,num); 78 } 79 Print_SeqStack(L); 80 printf("栈顶元素:%d\n",Top_SeqStack(L)); 81 printf("请输入要出栈的元素个数(不能超过%d个):\n",n); 82 scanf("%d",&n); 83 printf("依次出栈的%d个元素:\n",n); 84 for(i=0;i<n;i++) 85 { 86 Pop_SeqStack(L,&m); 87 printf("%3d",m); 88 } 89 printf("\n"); 90 Print_SeqStack(L); 91 printf("栈顶元素:%d\n",Top_SeqStack(L)); 92 return 0; 93 }
借助百度百科对于栈的介绍,利用链表的形式建了个栈,可以实现基本的操作,如进栈、出栈、判断空、打印栈中元素、返回栈顶元素。
听学长讲,貌似可以调用#include<vector>库实现对栈的操作。
栈在程序设计时有很多应用,举个最近正在用的例子,算术表达式求值。
例如对于中缀表达式3/5+8,将其改写为后缀表达式形式3 5 / 8 +,这就可以用栈进行计算了。
运算原理就是碰到数字就进栈,碰到运算符就取出栈顶前两个元素和此运算符进行运算,得到的数字再进栈,最后栈里的唯一元素即为值。
如1 2 + 8 2 - 7 4 - / *
步骤 | 栈中元素 | 说明 |
1 | 1 | 1进栈 |
2 | 12 | 2进栈 |
3 | 遇+号退栈2和1 | |
4 | 3 | 1+2=3的结果3进栈 |
5 | 38 | 8进栈 |
6 | 382 | 2进栈 |
7 | 3 | 遇-号退栈2和8 |
8 | 36 | 8-2=6的结果6进栈 |
9 | 367 | 7进栈 |
10 | 3674 | 4进栈 |
11 | 36 | 遇-号退栈4和7 |
12 | 36 | 7-4=3的结果3进栈 |
13 | 3 | 遇/号退栈3和6 |
14 | 32 | 6/3=2的结果2进栈 |
15 | 遇*号退栈2和3 | |
16 | 6 | 3*2=6进栈 |
17 | 6 | 扫描完毕,运算结束 |
中缀表达式转后缀表达式算法则为,建一个空栈存放运算符,遇到数字直接输出,并输出一个空格分隔开两个数字,遇到运算符则与栈顶元素比较优先级,大于就进栈,否则推出栈顶元素并输出,并输出一个空格分隔,遇到左括号进栈,遇到右括号则一直退栈输出,直到退到左括号止。当栈变成空时,输出的结果即为后缀表达式。
如(1+2)*((8-2)/(7-4))
步骤 | 栈中元素 | 输出结果 | 说明 |
1 | ( | (进栈 | |
2 | ( | 1 | 输出1 |
3 | (+ | 1 | +进栈 |
4 | (+ | 1 2 | 输出2 |
5 | 1 2 + | +退栈输出,退栈到(止 | |
6 | * | 1 2 + | *进栈 |
7 | *( | 1 2 + | (进栈 |
8 | *(( | 1 2 + | (进栈 |
9 | *(( | 1 2 + 8 | 输出8 |
10 | *((- | 1 2 + 8 | 输出2 |
11 | *((- | 1 2 + 8 2 | - 进栈 |
12 | *( | 1 2 + 8 2 - | -退栈输出,退栈到(止 |
13 | *(/ | 1 2 + 8 2 - | / 进栈 |
14 | *(/( | 1 2 + 8 2 - | ( 进栈 |
15 | *(/( | 1 2 + 8 2 - 7 | 输出7 |
16 | *(/(- | 1 2 + 8 2 - 7 | -进栈 |
17 | *(/(- | 1 2 + 8 2 - 7 4 | 输出4 |
18 | *(- | 1 2 + 8 2 - 7 4 - | -退栈输出,退栈到(止 |
19 | * | 1 2 + 8 2 - 7 4 - / | /退栈输出,退栈到(止 |
20 | 1 2 + 8 2 - 7 4 - / * | *退栈并输出 |