一、栈的定义
1.1 栈的定义
栈是一种特殊的数据结构,它的特点是后进先出(Last In First Out,LIFO)。栈是一种线性结构,它可以用来存储一组具有相同类型的数据元素。栈的基本操作包括压入(push)和弹出(pop),其中压入操作将数据元素添加到栈的顶部,弹出操作将栈顶的数据元素移除并返回。
1.2 栈的特点
栈的特点包括:
-
后进先出:栈中最后一个添加的元素最先被弹出。
-
只能在栈顶进行操作:栈的操作只能在栈顶进行,不能在中间或底部操作,因为栈是一种先进后出的结构。
-
可以用数组或链表实现:栈可以用数组或链表来实现,数组实现的栈需要指定栈的大小,而链表实现的栈可以动态扩展。
-
存储空间受限:栈的存储空间是有限的,一旦达到栈的存储上限,就会出现栈溢出的问题。
-
可以用递归实现:栈也可以通过递归的方式来实现,每次递归函数调用都会将参数和返回地址压入栈中,直到递归结束,最后按照相反的顺序弹出栈中的元素。
二、栈的实现使用与应用
2.1 栈的接口定义
typedef int DataType;
typedef struct
{
DataType *data; /* 堆空间 */
int maxsize;
int top; /* 栈顶指针 */
}SeqStack;
/* 1. 初始化 */
int init(SeqStack *S, int MaxSize);
/* 2. 进(入)栈 */
int push(SeqStack *S, DataType x);
/* 3. 出栈 */
int pop(SeqStack *S, DataType *x);
/* 4. 取栈顶元素 */
int get_top(SeqStack *S, DataType *x);
/* 5. 栈为空?*/
int empty(SeqStack *S);
/* 6. 栈满?*/
int full(SeqStack *S);
/* 7. 销毁*/
int destroy(SeqStack *S);
2.2 栈的实现
2.2.1 栈的初始化
int init(SeqStack *S, int MaxSize)
{
/*申请内存空间*/
S->data = (DataType*)malloc(sizeof(DataType)*MaxSize);
if(!S->data)
{
printf("内存申请错误,初始化失败![10001]\n");
return 10001;
}
S->maxsize = MaxSize;
S->top = -1;
return 0;
}
2.2.2 入栈
int push(SeqStack *S, DataType x)
{
/*是否满?*/
if(full(S))
{
printf("栈已满!10002\n");
return 10002;
}
S->top++; /*移动指针*/
S->data[S->top] = x;/*放入数据*/
return 0; /*OK*/
}
2.2.3 出栈
int pop(SeqStack *S, DataType *x)
{
/*是否空?*/
if(empty(S))
{
printf("栈为空!10003\n");
return 10003;
}
*x = S->data[S->top]; /*栈顶元素赋值给x*/
S->top--; /*移动栈顶指针*/
return 0;
}
2.2.4 查找栈顶元素
int get_top(SeqStack *S, DataType *x)
{
/*是否空?*/
if(empty(S))
{
printf("栈为空!10003\n");
return 10003;
}
*x = S->data[S->top]; /*栈顶元素赋值给x*/
return 0;
}
2.2.5 判断栈是否为空
int empty(SeqStack *S)
{
return (S->top == -1)?1:0;
}
2.2.6 判断栈是否已满
int full(SeqStack *S)
{
return (S->top == S->maxsize - 1)?1:0;
}
2.2.7 销毁栈
int destroy(SeqStack *S)
{
free(S->data);
return 0;
}
2.3栈的应用
2.3.1十进制转二进制
int d_to_b(int d)
{
SeqStack S;
int b;
/*初始化栈*/
init(&S,32);
/*d不为0,余数进栈*/
while(d)
{
push(&S, d % 2);
d /= 2;
}
/*依次出栈*/
while(!empty(&S))
{
pop(&S,&b);
printf("%d", b);
}
/*销毁栈*/
destroy(&S);
}
2.3.2后缀表达式计算
int expression()
{
SeqStack S;
int i;
int op1, op2;
int x;
char exp[20]; /*后缀表达式*/
init(&S, 10);
printf("请输入一个后缀表达式(eg. 56+):");
scanf("%s", exp);
for(i=0;i<strlen(exp);i++)
{
switch(exp[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*入栈*/
push(&S, exp[i]-48);
printf("%c\n",exp[i]);
break;
case '+':
/*出2个*/
pop(&S, &op1);
pop(&S, &op2);
x = op1 + op2;
push(&S, x);
break;
case '*':
pop(&S, &op1);
pop(&S, &op2);
x = op1 * op2;
push(&S, x);
break;
case '-':
pop(&S, &op1);
pop(&S, &op2);
x = op2- op1;
push(&S, x);
break;
case '/':
pop(&S, &op1);
pop(&S, &op2);
x = op2/op1;
push(&S, x);
break;
}
}
pop(&S, &x);
printf("计算结果为:%s = %d\n", exp, x);
destroy(&S);
}
2.4栈的使用
#include <stdio.h>
#include "seqstack.h"
#include "welcome.h"
int main(int argc, char* argv[])
{
SeqStack S;
DataType x;
int maxsize;
char yn;
int i,m,n,cmd,d;
;
for(i=0;i<strlen(welcome);i++)
{
printf("%c",welcome[i]);
for(m=0;m<1000;m++)
for(n=0;n<1000;n++)
{
;
}
}
printf("---------顺序栈演示程序-----------\n");
do
{
printf(" 1. 初始化\n");
printf(" 2. 入栈\n");
printf(" 3. 出栈\n");
printf(" 4. 查找栈顶元素\n");
printf(" 5. 判断栈为是否空\n");
printf(" 6. 判断栈为是否满\n");
printf(" 7. 销毁栈\n");
printf(" 8. 栈的应用\n");
printf(" 9. 帮助\n");
printf("请选择(0~9,0退出):");
scanf("%d", &cmd);
switch(cmd)
{
case 1:
printf("请输入栈的最大存储空间(MaxSize):");
scanf("%d", &maxsize);
if(!init(&S, maxsize))
{
printf("栈已初始化!\n");
}
break;
case 2:
printf("请输入入栈元素:x=");
scanf("%d", &x);
if(!push(&S, x))
{
printf("元素【%d】已入栈!\n", x);
}
break;
case 3:
printf("确定要出栈(出栈后数据不可恢复,y|n,n)?");
fflush(stdin);
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y')
{
if(!pop(&S, &x))
{
printf("栈顶元素【%d】已出栈!\n", x);
}
}
break;
case 4:
if(!get_top(&S,&x)){
printf("查找到栈顶元素[%d]\n",x);
}
break;
case 5:
if(empty(&S)){
printf("栈为空!\n");
}else{
printf("栈内存在元素\n");
}
break;
case 6:
if(full(&S)){
printf("栈满!\n");
}else{
printf("栈未满\n");
}
break;
case 7:
destroy(&S);
printf("栈已销毁\n");
break;
case 8:
do
{
printf("----------8.栈的应用------------\n");
printf(" 1. 十进制转换为二进制\n");
printf(" 2. 后缀表达式计算\n");
printf(" 0. 返回\n");
printf("请选择:");
scanf("%d", &cmd);
if(cmd == 1)
{
printf("请输入一个十进制数:");
scanf("%d", &d);
printf("二进制为:");
d_to_b(d);
printf("\n");
}
if(cmd == 2)
{
expression();
}
}while(cmd!=0);
cmd = -1;
break;
case 9:
printf(" 本程序为栈的演示程序,由黄彬森设计开发,程序完成了栈的基本功能!\n");
default:
printf("输入选项不存在\n");
}
}while(cmd!=0);
return 0;
}
/*十进制转换为二进制*/
int d_to_b(int d)
{
SeqStack S;
int b;
/*初始化栈*/
init(&S,32);
/*d不为0,余数进栈*/
while(d)
{
push(&S, d % 2);
d /= 2;
}
/*依次出栈*/
while(!empty(&S))
{
pop(&S,&b);
printf("%d", b);
}
/*销毁栈*/
destroy(&S);
}
/*后缀表达式计算*/
int expression()
{
SeqStack S;
int i;
int op1, op2;
int x;
char exp[20]; /*后缀表达式*/
init(&S, 10);
printf("请输入一个后缀表达式(eg. 56+):");
scanf("%s", exp);
for(i=0;i<strlen(exp);i++)
{
switch(exp[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*入栈*/
push(&S, exp[i]-48);
printf("%c\n",exp[i]);
break;
case '+':
/*出2个*/
pop(&S, &op1);
pop(&S, &op2);
x = op1 + op2;
push(&S, x);
break;
case '*':
pop(&S, &op1);
pop(&S, &op2);
x = op1 * op2;
push(&S, x);
break;
case '-':
pop(&S, &op1);
pop(&S, &op2);
x = op2- op1;
push(&S, x);
break;
case '/':
pop(&S, &op1);
pop(&S, &op2);
x = op2/op1;
push(&S, x);
break;
}
}
pop(&S, &x);
printf("计算结果为:%s = %d\n", exp, x);
destroy(&S);
}
三、完整代码
3.1 main.c文件代码
#include <stdio.h>
#include "seqstack.h"
#include "welcome.h"
int main(int argc, char* argv[])
{
SeqStack S;
DataType x;
int maxsize;
char yn;
int i,m,n,cmd,d;
;
for(i=0;i<strlen(welcome);i++)
{
printf("%c",welcome[i]);
for(m=0;m<1000;m++)
for(n=0;n<1000;n++)
{
;
}
}
printf("---------顺序栈演示程序-----------\n");
do
{
printf(" 1. 初始化\n");
printf(" 2. 入栈\n");
printf(" 3. 出栈\n");
printf(" 4. 查找栈顶元素\n");
printf(" 5. 判断栈为是否空\n");
printf(" 6. 判断栈为是否满\n");
printf(" 7. 销毁栈\n");
printf(" 8. 栈的应用\n");
printf(" 9. 帮助\n");
printf("请选择(0~9,0退出):");
scanf("%d", &cmd);
switch(cmd)
{
case 1:
printf("请输入栈的最大存储空间(MaxSize):");
scanf("%d", &maxsize);
if(!init(&S, maxsize))
{
printf("栈已初始化!\n");
}
break;
case 2:
printf("请输入入栈元素:x=");
scanf("%d", &x);
if(!push(&S, x))
{
printf("元素【%d】已入栈!\n", x);
}
break;
case 3:
printf("确定要出栈(出栈后数据不可恢复,y|n,n)?");
fflush(stdin);
scanf("%c", &yn);
if(yn == 'y' || yn == 'Y')
{
if(!pop(&S, &x))
{
printf("栈顶元素【%d】已出栈!\n", x);
}
}
break;
case 4:
if(!get_top(&S,&x)){
printf("查找到栈顶元素[%d]\n",x);
}
break;
case 5:
if(empty(&S)){
printf("栈为空!\n");
}else{
printf("栈内存在元素\n");
}
break;
case 6:
if(full(&S)){
printf("栈满!\n");
}else{
printf("栈未满\n");
}
break;
case 7:
destroy(&S);
printf("栈已销毁\n");
break;
case 8:
do
{
printf("----------8.栈的应用------------\n");
printf(" 1. 十进制转换为二进制\n");
printf(" 2. 后缀表达式计算\n");
printf(" 0. 返回\n");
printf("请选择:");
scanf("%d", &cmd);
if(cmd == 1)
{
printf("请输入一个十进制数:");
scanf("%d", &d);
printf("二进制为:");
d_to_b(d);
printf("\n");
}
if(cmd == 2)
{
expression();
}
}while(cmd!=0);
cmd = -1;
break;
case 9:
printf(" 本程序为栈的演示程序,由黄彬森设计开发,程序完成了栈的基本功能!\n");
default:
printf("输入选项不存在\n");
}
}while(cmd!=0);
return 0;
}
/*十进制转换为二进制*/
int d_to_b(int d)
{
SeqStack S;
int b;
/*初始化栈*/
init(&S,32);
/*d不为0,余数进栈*/
while(d)
{
push(&S, d % 2);
d /= 2;
}
/*依次出栈*/
while(!empty(&S))
{
pop(&S,&b);
printf("%d", b);
}
/*销毁栈*/
destroy(&S);
}
/*后缀表达式计算*/
int expression()
{
SeqStack S;
int i;
int op1, op2;
int x;
char exp[20]; /*后缀表达式*/
init(&S, 10);
printf("请输入一个后缀表达式(eg. 56+):");
scanf("%s", exp);
for(i=0;i<strlen(exp);i++)
{
switch(exp[i])
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/*入栈*/
push(&S, exp[i]-48);
printf("%c\n",exp[i]);
break;
case '+':
/*出2个*/
pop(&S, &op1);
pop(&S, &op2);
x = op1 + op2;
push(&S, x);
break;
case '*':
pop(&S, &op1);
pop(&S, &op2);
x = op1 * op2;
push(&S, x);
break;
case '-':
pop(&S, &op1);
pop(&S, &op2);
x = op2- op1;
push(&S, x);
break;
case '/':
pop(&S, &op1);
pop(&S, &op2);
x = op2/op1;
push(&S, x);
break;
}
}
pop(&S, &x);
printf("计算结果为:%s = %d\n", exp, x);
destroy(&S);
}
3.2 seqstack.h文件代码
typedef int DataType;
typedef struct
{
DataType *data; /* 堆空间 */
int maxsize;
int top; /* 栈顶指针 */
}SeqStack;
/* 1. 初始化 */
int init(SeqStack *S, int MaxSize);
/* 2. 进(入)栈 */
int push(SeqStack *S, DataType x);
/* 3. 出栈 */
int pop(SeqStack *S, DataType *x);
/* 4. 取栈顶元素 */
int get_top(SeqStack *S, DataType *x);
/* 5. 栈为空?*/
int empty(SeqStack *S);
/* 6. 栈满?*/
int full(SeqStack *S);
/* 7. 销毁*/
int destroy(SeqStack *S);
3.3 seqstack.c文件代码
#include "seqstack.h"
/* 1. 初始化 */
int init(SeqStack *S, int MaxSize)
{
/*申请内存空间*/
S->data = (DataType*)malloc(sizeof(DataType)*MaxSize);
if(!S->data)
{
printf("内存申请错误,初始化失败![10001]\n");
return 10001;
}
S->maxsize = MaxSize;
S->top = -1;
return 0;
}
/* 2. 进(入)栈 */
int push(SeqStack *S, DataType x)
{
/*是否满?*/
if(full(S))
{
printf("栈已满!10002\n");
return 10002;
}
S->top++; /*移动指针*/
S->data[S->top] = x;/*放入数据*/
return 0; /*OK*/
}
/* 3. 出栈 */
int pop(SeqStack *S, DataType *x)
{
/*是否空?*/
if(empty(S))
{
printf("栈为空!10003\n");
return 10003;
}
*x = S->data[S->top]; /*栈顶元素赋值给x*/
S->top--; /*移动栈顶指针*/
return 0;
}
/* 4. 取栈顶元素 */
int get_top(SeqStack *S, DataType *x)
{
/*是否空?*/
if(empty(S))
{
printf("栈为空!10003\n");
return 10003;
}
*x = S->data[S->top]; /*栈顶元素赋值给x*/
return 0;
}
/* 5. 栈为空?*/
int empty(SeqStack *S)
{
return (S->top == -1)?1:0;
}
/* 6. 栈满?*/
int full(SeqStack *S)
{
return (S->top == S->maxsize - 1)?1:0;
}
/* 7. 销毁*/
int destroy(SeqStack *S)
{
free(S->data);
return 0;
}
3.4 welcome.h文件代码
char welcome[] = "\n\
| .-.\n\
| / 、 .-.\n\
| / 、 / 、 .-. .-.\n\
+--/-------、-----/-----、-----/---、---/---、---/-、-/-、/、/---\n\
| / 、 / 、 / '-' '-' \n\
|/ '-' '-' \n\
";
四、代码运行结果
| .-.
| / 、 .-.
| / 、 / 、 .-. .-.
+--/-------、-----/-----、-----/---、---/---、---/-、-/-、/、/---
| / 、 / 、 / '-' '-'
|/ '-' '-'
---------顺序栈演示程序-----------
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):1
请输入栈的最大存储空间(MaxSize):10
栈已初始化!
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):2
请输入入栈元素:x=10
元素【10】已入栈!
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):2
请输入入栈元素:x=30
元素【30】已入栈!
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):4
查找到栈顶元素[30]
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):5
栈内存在元素
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):6
栈未满
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):3
确定要出栈(出栈后数据不可恢复,y|n,n)?y
栈顶元素【30】已出栈!
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):7
栈已销毁
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):8
----------8.栈的应用------------
1. 十进制转换为二进制
2. 后缀表达式计算
0. 返回
请选择:1
请输入一个十进制数:102
二进制为:1100110
----------8.栈的应用------------
1. 十进制转换为二进制
2. 后缀表达式计算
0. 返回
请选择:2
请输入一个后缀表达式(eg. 56+):34+4-2*2/
3
4
4
2
2
计算结果为:34+4-2*2/ = 3
----------8.栈的应用------------
1. 十进制转换为二进制
2. 后缀表达式计算
0. 返回
请选择:0
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):9
本程序为栈的演示程序,由黄彬森设计开发,程序完成了栈的基本功能!
输入选项不存在
1. 初始化
2. 入栈
3. 出栈
4. 查找栈顶元素
5. 判断栈为是否空
6. 判断栈为是否满
7. 销毁栈
8. 栈的应用
9. 帮助
请选择(0~9,0退出):0
--------------------------------
Process exited after 128.2 seconds with return value 0
请按任意键继续. . .
五、小结
栈是一种特殊的顺序结构,栈存储方式以先入后出,后入先出的原则存储数据。入栈时添加元素会置于栈的栈顶,出栈时也需元素从栈顶处出栈,栈可以通过数组和链表实现,链表实现相对简单些,并且链表可以动态扩展,。
六、参考文献
【1】CSDN
【2】数据结构(C语言)