顺序栈的定义以及特点
定义:
顺序栈(Sequential Stack)是一种基于数组实现的栈结构。栈是一种后进先出(LIFO)的数据结构,只能在栈顶进行插入和删除操作。顺序栈的定义如下:
-
数据结构:顺序栈由一个固定大小的数组和一个指向栈顶的指针组成。
-
操作:
- 初始化:创建一个空栈,将栈顶指针指向-1。
- 入栈(Push):将元素压入栈顶,栈顶指针加1。
- 出栈(Pop):将栈顶元素弹出,栈顶指针减1。
- 获取栈顶元素(Top):返回栈顶元素的值,但不删除。
- 判空(IsEmpty):判断栈是否为空,即栈顶指针是否为-1。
- 判满(IsFull):判断栈是否已满,即栈顶指针是否达到数组的最大索引。
特点:
顺序栈的特点如下:
-
存储效率高:顺序栈使用数组来存储数据,因此存储效率高,不需要额外的指针域。
-
访问速度快:由于栈的特性,只能在栈顶进行插入和删除操作,因此访问速度快。
-
需要预先分配固定大小的内存空间:顺序栈需要预先分配一定大小的数组来存储数据,因此需要提前确定栈的最大容量。
-
容量固定:由于数组大小是固定的,顺序栈的容量是固定的,无法动态扩展。
-
可能存在溢出问题:当栈满时,再进行入栈操作会导致栈溢出。
总之,顺序栈是一种简单、高效的栈实现方式,适用于已知大小的栈场景。但需要注意容量的限制和溢出问题。
顺序栈的基本运算
包括初始化、入栈、出栈、获取栈顶元素、判空和判满。下面是对每个运算的详细描述:
-
初始化(Init):创建一个空栈,将栈顶指针指向-1。
-
入栈(Push):将元素压入栈顶,栈顶指针加1。
- 首先判断栈是否已满(IsFull)。
- 如果栈未满,则将元素放入栈顶位置(栈顶指针加1),并将元素存入数组中。
-
出栈(Pop):将栈顶元素弹出,栈顶指针减1。
- 首先判断栈是否为空(IsEmpty)。
- 如果栈非空,则将栈顶元素取出并返回(栈顶指针减1)。
-
获取栈顶元素(Top):返回栈顶元素的值,但不删除。
- 首先判断栈是否为空(IsEmpty)。
- 如果栈非空,则返回栈顶位置的元素值。
-
判空(IsEmpty):判断栈是否为空,即栈顶指针是否为-1。
- 如果栈顶指针为-1,则表示栈为空,返回真(True)。
- 否则,栈非空,返回假(False)。
-
判满(IsFull):判断栈是否已满,即栈顶指针是否达到数组的最大索引。
- 如果栈顶指针等于数组的最大索引,则表示栈已满,返回真(True)。
- 否则,栈未满,返回假(False)。
以上是顺序栈的基本运算,它们共同构成了对栈的常用操作。通过这些运算,可以实现栈的基本功能,如入栈、出栈、获取栈顶元素等。需要注意的是,在进行入栈和出栈操作时,需要先判断栈是否已满或为空,以避免溢出或下溢的问题。
顺序栈的实现
初始化栈
/* 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;
}
顺序栈的应用部分
/*十进制转换为二进制*/
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);
}
运行截图
完整Demo
main.c部分
#include <stdio.h>
#include <string.h>
#include "seqstack.c"
#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);
}
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;
}
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);
welcome.h部分
char welcome[] = "\n\
............\n\
................\n\
..................\n\
....................\n\
....................\n\
..................\n\
....\ ............../\n\
........... .........................\n\
..............\ /......../######\....../###\.\n\
................v.........##########\...#######\n\
..........................|######/..\##.|####/.\#| ....\n\
..................#####\.,|######....##.|####...#| .......\n\
................|########.|######....##.|####...#| .......\n\
...............#########_|######\../##.|####\./#| /##\....\n\
..............###############################nn\/#######^\n\
\........./ \########~##############nnnnn.###########/\n\
########|##########nnnnn.##############/\n\
#######| \###########################/\n\
\###.##\ \######################\n\
\##.##\ ___ \#############/\n\
\.##\/.../..\ /##/\n\
\##\/..../ /####/\n\
\#############/\n\
Welcome to the mouse program\n\n";
顺序栈学习小结
学习顺序栈是学习数据结构中的重要一步。顺序栈是一种简单、高效的栈实现方式,适用于已知大小的栈场景。学习顺序栈可以帮助我们理解栈的基本概念和操作,并能够灵活运用栈来解决实际问题。
在学习顺序栈时,我们需要掌握以下几个关键点:
-
栈的特点:顺序栈具有后进先出(LIFO)的特点,只能在栈顶进行插入和删除操作。
-
栈的基本运算:顺序栈的基本运算包括初始化、入栈、出栈、获取栈顶元素、判空和判满等操作。
-
存储结构:顺序栈使用数组来存储数据,因此存储效率高,不需要额外的指针域。
-
容量限制和溢出问题:顺序栈需要预先分配一定大小的数组来存储数据,因此容量是固定的。当栈满时,再进行入栈操作会导致栈溢出。
-
应用场景:顺序栈适用于已知大小的栈场景,如表达式求值、括号匹配、逆波兰表达式等问题。
通过学习顺序栈,我们能够加深对栈的理解,并能够将栈的概念和操作应用到实际问题中。同时,顺序栈也是其他栈的实现方式的基础,对于后续学习其他栈的实现方式也具有重要的参考价值。