一、顺序栈的基本概念 顺序栈是指利用顺序存储结构实现的栈,是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端

一、顺序栈的基本概念

顺序栈是指利用顺序存储结构实现的栈,是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。

定义

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。

优缺点

优点:顺序栈在插入和删除时候不需要移动元素,只需移动top指针。

缺点:顺序栈和顺序表一样,都需要预先定好数组空间,不像链表那样机动

二、代码实现

1、定义接口

/*

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);

2、实现接口

2.1 初始化栈

/* 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.3 出栈操作

/* 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.4 取栈顶元素

/* 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.5 判断栈是否为空

/* 5. 栈空*/

int empty(SeqStack *S)

{

return (S->top == -1)?1:0;

}

2.6 判断栈是否已满

/*6. 栈满*/

int full(SeqStack *S)

{

return (S->top == S->maxsize - 1)?1:0;

}

2.7 销毁栈

/* 7. 销毁*/

int destroy(SeqStack *S)

{

free(S->data);

return 0;

}

2.8 扩展练习

2.8.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.8.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

{

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);

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);

if(op1 == 0){

printf("除数不能为零!请重新输入");

destroy(&S);

return 0;

}

x = op2 / op1;

push(&S, x);

break;

}

}

pop(&S, &x);

printf("计算结果为:%s = %d\n", exp, x);

destroy(&S);

}

2.9 main方法

#include

#include

#include "seqstack.h"

/*十进制转换为二进制*/

int d_to_b(int d);

/*后缀表达式计算*/

int expression();

char welcome[] = "////////////////////////////////////////////////////////////////////\n// _ooOoo_ //\n// o8888888o //\n// 88”.“88 //\n// (| ^_^ |) //\n// O\ = /O //\n// ____/`---'\____ //\n// .' \\| |// `. //\n// / \\||| : |||// \ //\n// / _||||| -:- |||||- \ //\n// | | \\\ - /// | | //\n// | \_| ''\---/'' | | //\n// \ .-\__ `-` ___/-. / //\n// ___`. .' /--.--\ `. . ___ //\n// .‘’ '< `.___\_<|>_/___.' >' ‘’. //\n// | | : `- \`.;`\ _ /`;.`/ - ` : | | //\n// \ \ `-. \_ __\ /__ _/ .-` / / //\n// ========`-.____`-.___\_____/___.-`____.-'======== //\n// `=---=' //\n// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //\n// 佛祖保佑 永不宕机 永无BUG //\n////////////////////////////////////////////////////////////////////\n";

int main(int argc, char* argv[])

{

SeqStack S;

int cmd;

int d;

DataType x;

int maxsize;

char yn;

for(int i=0;i

{

printf("%c",welcome[i]);

for(int m=0;m<10000;m++)

for(int n=0;n<300;n++)

{

}

}

do

{

printf("---------顺序栈演示程序-----------\n");

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. 退出\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)?");

// flushall();

fflush(stdin);

scanf("%c", &yn);

if(yn == 'y' || yn == 'Y')

{

if(!pop(&S, &x))

{

printf("栈顶元素【%d】已出栈!\n", x);

}

}

break;

case 4:

get_top(&S,&x);

if(!get_top(&S,&x))

{

printf("栈顶元素为【%d】\n",x);

}

break;

case 5:

if (empty(&S) == 0)

{

printf("这个栈不是空的!\n");

}else

{

printf("这个栈是空的!\n");

}

break;

case 6:

if (full(&S) == 0)

{

printf("这个栈不是满的!\n");

}else

{

printf("这个栈满啦!\n");

}

break;

case 7:

printf("确定要销毁(销毁后数据不可恢复,y|n,n)?");

fflush(stdin);

scanf("%c", &yn);

if(yn == 'y' || yn == 'Y')

{

if(!destroy(&S.data))

{

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");

break;

case 0:

break;

}

}while(cmd!=0);

return 0;

}

3、运行结果图

四、小结

顺序栈具有简单易懂、内存连续和存取效率高等优点。然而,它也存在大小固定、存储空间浪费和栈满溢出等缺点。

顺序栈的优点之一是它的实现相对简单。没有复杂的指针操作,顺序栈易于理解和使用。

另一个优点是顺序栈的内存连续性。栈中的元素在内存中是连续存储的,这使得访问栈中的元素非常高效。在大多数情况下,顺序栈的存取速度非常高。

然而,顺序栈也有一些缺点需要考虑。首先,顺序栈的大小在创建时就已经确定,并且无法动态调整。如果栈的容量不够大,当栈满时无法再添加新的元素。这意味着在使用顺序栈时,需要提前估计栈的大小,并确保足够的存储空间。

其次,顺序栈可能存在存储空间浪费的问题。由于顺序栈的大小是固定的,即使栈中只有很少的元素,它仍然会占用一定的存储空间。这会导致存储空间的浪费,尤其是当栈的容量远大于实际需要的元素数量时。

最后,顺序栈还需要注意栈满溢出的问题。如果栈已满,再进行入栈操作会导致数据丢失或程序崩溃。

总的来说,顺序栈是一种简单、高效的栈数据结构。它适用于那些栈大小固定且不需要频繁调整的场景。但是,如果需要一个可以动态调整大小的栈,或者对存储空间利用效率有更高要求的话,可能需要考虑其他类型的栈实现,如链式栈。

参考文献

百度百科、CSDN、数据结构(C语言版)