来源:互联网 发布:网络发票查询 编辑:程序博客网 时间:2024/05/29 15:28

1、栈(stack)是限定仅在表尾进行插入和删除操作的线性表。(表尾指栈顶)

---- 把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。

栈又称为先进后出/后进先出(Last In First Out)的线性表,简称LIFO结构。

理解栈的定义需要注意:

---- 首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。

它的特殊之处就在于限制了这个线性表的插入和删除位置,它始终只在栈顶进行。

这也就使得:栈底是固定的,最先进栈的只能在栈底。

---- 栈的插入操作,叫做进栈,也称压栈、入栈(Push)。栈的删除操作,叫做出栈,有的叫做弹栈(Pop)

2、栈的顺序存储结构

---- 栈是线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,简称为顺序栈。顺序表是用数组来实现的。

定义一个top变量来指示栈顶元素在数组中的位置,可以变化,但不能超过栈的长度StackSize。

当栈存在一个元素时,top=0,因此通常把空栈的判定条件定为 top=-1.

栈的结构定义:

#include <iostream>using namespace std;#define OK 1#define ERROR 0typedef int Status;#define MaxSize 50typedef int SElemtype;typedef struct{SElemtype stack[MaxSize];int top;} SqStack;

---- 进栈操作push和出栈操作pop
//进栈操作push,插入元素e为新的栈顶元素Status Push(SqStack *S,SElemtype e){if(S->top==MaxSize-1) //栈满return ERROR;S->top++;S->stack[S->top]=e;return OK;}//出栈操作pop,若栈不为空,则删除S的栈顶元素,用e返回其值Status pop(SqStack *S,SElemtype *e){if(S->top==-1)  //空栈return ERROR;*e=S->stack[S->top];//将要删除的栈顶元素赋值给eS->top--;//栈顶指针减1return OK;}

3、两栈共享空间

---- 用一个数组来存储两个栈,数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为

数组的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。

思路:两个栈在数组的两端,向中间靠拢。top1和top2是栈1和栈2的栈顶指针,可以想象,只要它们俩不见面,两个栈就可以一直使用。

栈1为空时,top1=-1,当栈2为空时,top2=n,当 top1 + 1 = top2 时,即两个栈顶元素相邻时,栈满。

两栈共享空间的结构的代码如下:

#define MaxSize 100 typedef struct{SElemtype stack[MaxSize];int top1;//栈1栈顶指针int top2;//栈2栈顶指针} SqDoubleStack;
对于两栈共享空间的push和pop方法,除了我们要插入和删除元素值参数外,还需要有一个判断是栈1还是栈2的栈号参数stacknumber。

插入和删除元素的代码如下:

Status Push(SqDoubleStack *S,SElemtype e,int stacknumber){if(S->top1+1 == S->top2) //栈已满,不能再push新元素了return ERROR;if(stacknumber == 1)//栈1有元素进栈S->stack[++S->top1]=e;//先top1+1后给数组元素赋值else if(stacknumber == 2)S->stack[--S->top2]=e;//先top2-1后给数组元素赋值return OK;}Status Pop(SqDoubleStack *S,SElemtype *e,int stacknumber){if(stacknumber==1){if(S->top1=-1)//栈1是空栈return ERROR;*e = S->stack[S->top1--];//将栈1的栈顶元素出栈}else if(stacknumber==2){if(S->top2==MaxSize)//栈2是空栈return ERROR;*e = S->stack[S->top2++];}return OK;}

事实上,使用这样的数据结构,通常都是当两个栈的空间需求有相反关系时,即一个栈在增长时另一个栈在缩短的情况。

并且这两个栈具有相同的数据类型。

4、栈的链式存储结构--链栈

---- 栈顶放在单链表的头部(插入和删除操作)。对于链栈来说,是不需要头结点的。对于链栈来说,基本不存在栈满的情况,除非内存已经

没有可以使用的空间。对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是top=NULL。

链栈的结构代码如下:

typedef int SElemtype;//结点typedef struct StackNode{SElemtype sdata;struct StackNode *next;}StackNode,*LinkStackPtr;//栈typedef struct LinkStack{LinkStackPtr top;//栈顶指针int count;//栈内元素个数}LinkStack;

进栈操作和出栈操作

Status Push(LinkStack *S,SElemtype e){LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));//创建新结点s->sdata = e;s->next = S->top;//把当前的栈顶元素赋值给新结点的直接后继S->top = s;S->count++;return OK;}Status Pop(LinkStack *S,SElemtype *e){LinkStackPtr p;if(S->top==NULL)//链栈为空return ERROR;*e = S->top->sdata;p = S->top;S->top = S->top->next;free(p);S->count--;return OK;}
链栈的进栈Push和出栈Pop操作都很简单,没有任何循环操作,时间复杂度均为O(1)。

对比一下顺序栈与链栈,它们在时间复杂度上是一样的,均为O(1)。对于空间复杂度,顺序栈需要事先确定一个固定的长度,可能会

存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但

对于栈的长度无限制。

---- 如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈。

反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。







0 0
原创粉丝点击