顺序栈链栈双端栈
Posted tianzeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了顺序栈链栈双端栈相关的知识,希望对你有一定的参考价值。
定义
栈(Stack)又称堆栈,它是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算。 由于栈的插入和删除运算仅在栈顶一端进行,后进栈的元素必定先出栈,所以又把栈称为后进先出表(Last In First Out, 简称LIFO)。
栈的存储结构
一:顺序存储
栈的顺序存储结构同样需要使用一个数组和一个整型变量来实现,利用数组来顺序存储栈中的所有元素,利用整型变量来存储栈顶元素的下标位置
typedef struct Node { int data[max]; int top; }SeqStack;
max为一个整型全局常量,需事先通过const语句定义,由它确定顺序栈(即顺序存储的栈)的最大深度,又称为长度,即栈最多能够存储的元素个数;由于top用来指示栈顶元素的位置,所以把它称为栈顶指针。
在顺序存储的栈中,top的值为-1表示栈空,每次向栈中压入一个元素时,首先使top增1,用以指示新的栈顶位置,然后再把元素赋值到这个位置上,每次从栈中弹出一个元素时,首先取出栈顶元素,然后使top减1,指示前一个元素成为新的栈顶元素。由此可知,对顺序栈的插入和删除运算相当于是在顺序表(即顺序存储的线性表)的表尾进行的,其时间复杂度为O(1)。
1.初始化栈
void InitStack(Stack& S) // 初始化栈S,即把它置为空 { S.top=-1; }
2.把一个栈清除为空
void ClearStack(Stack& S)// 清除栈S中的所有元素,使之成为一个空栈,在顺序存储方式下,同初始化栈的算法相同。 { S.top=-1; }
3.检查一个栈是否为空
int StackEmpty(Stack& S) // 判断S是否为空,若是则返回1,否则返回0 { return S.top==-1; }
4. 读取栈顶元素
ElemType Peek(StackType& S)// 返回S的栈顶元素,但不移动栈顶指针 { //若栈为空则终止程序运行 if(S.top==-1) { cerr<<"Stack is empty!"<<endl; exit(1); } //返回栈顶元素的值 return S.stack[S.top]; }
5.进栈
void Push(Stack& S, const ElemType& item)// 元素item进栈,即插入到栈顶 { //若栈已满则终止程序运行 if(S.top==StackMaxSize-1) { cerr<<"Stack overflow!"<<endl; exit(1); } //将栈顶指针后移一个位置 S.top++; //将item的值赋给新的栈顶位置 S.stack[S.top]=item; }
6.出栈
ElemType Pop(StackType& S)// 删除栈顶元素并返回之 { // 若栈为空则终止程序运行 if(S.top==-1) { cerr<<"Stack is empty!"<<endl; exit(1); } // 暂存栈顶元素以便返回 ElemType temp=S.stack[S.top]; // 栈顶指针前移一个位置 S.top--; // 返回原栈顶元素的值 return temp; }
从出栈算法可以看出,原栈顶元素的值没有被改变,所以可以不使用临时变量保存它,返回语句中返回S.stack[S.top+1]的值即可
7.检查栈是否已满
int StackFull(Stack& S)// 若栈已满则返回1,否则返回0,此函数为顺序栈所特有 { return S.top==StackMaxSize-1; }
完整代码
#include<stdio.h> #define max 3 typedef struct Node { int data[max]; int top; }SeqStack; void InitStack(SeqStack *s) { s->top=-1; } void Push(SeqStack *s,int a[],int k) { if(s->top==max-1) { printf("The stack is full! "); return; } else { for(int i=0;i<=k;i++) { s->top++; s->data[s->top]=a[i]; } printf("Successful entry into the stack! "); return; } } void Print(SeqStack *s) { printf("Data in the Stack: "); for(int i=0;i<=s->top;i++) printf("%-3d",s->data[i]); printf(" "); } int Pop(SeqStack *s) { if(s->top==-1) { printf("Stack empty! "); return -1; } else { s->top--; printf("Successful leave into the stack! "); } } void P_rint(SeqStack *s) { printf("Now data in the Stack is: "); for(int i=0;i<=s->top;i++) printf("%-3d",s->data[i]); printf(" "); } int main() { int a[max],k=-1,x,result; SeqStack s; InitStack(&s); printf("Please input the data: "); for(int i=0;i<max;i++) { scanf("%d",&x); if(x==0) break; a[i]=x; k++; } Push(&s,a,k); Print(&s); result=Pop(&s); if(result==-1) return 0; P_rint(&s); return 0; }
二:链式存储
栈的链接存储结构与线性表的链接存储结构相同,是通过由结点构成的单链表实现的,此时表头指针被称为栈顶指针,由栈顶指针指向的表头结点被称为栈顶结点,整个单链表被称为链栈,即链接存储的栈。当向一个链栈插入元素时,是把该元素插入到栈顶,即使该元素结点的指针域指向原来的栈顶结点,而栈顶指针则修改为指向该元素结点,使该结点成为新的栈顶结点。当从一个链栈中删除元素时,是把栈顶元素结点删除掉,即取出栈顶元素后,使栈顶指针指向原栈顶结点的后继结点。由此可知,对链栈的插入和删除操作是在单链表的表头进行的,其时间复杂度为O(1)。
1.初始化链栈
void InitStack(LNode*& HS) { HS=NULL; // 将链栈置空。 }
2.清除链栈为空
void ClearStack(LNode*& HS) { LNode *cp, *np; // 用cp作为指向待删除的结点,np指向cp的后继结点。 cp=HS; // 给cp指针赋初值,使之指向栈顶结点。 while(cp!=NULL) { // 从栈顶到栈底依次删除每个结点 np=cp->next; delete cp; cp=np; } HS=NULL; // 置链栈为空 }
3.检查链栈是否为空
int StackEmpty(LNode* HS)// HS为值参或引用形参均可 { return HS==NULL; }
4.读取栈顶元素
ElemType Peek(LNode* HS) // HS为值参或引用形参均可 { if(HS==NULL) { cerr<<"Linked stack is empty!"<<endl; exit(1); } return HS->data; }
5.进栈
void Push(LNode*& HS, const ElemType& item) { // 为插入元素获取动态结点 LNode* newptr= new LNode; if(newptr==NULL) { cerr<<"Memory allocation failare!"<<endl; exit(1); } // 给新分配的结点赋值 newptr->data=item; // 向栈顶插入新结点 newptr->next=HS; HS=newptr; }
6.出栈
ElemType Pop(LNode*& HS) { if(HS==NULL) { cerr<<"Linked stack is empty!"<<endl; exit(1); } LNode* p=HS; // 暂存栈顶结点 HS=HS->next; // 使栈顶指针指向其后继结点 ElemType temp=p->data; // 暂存原栈顶元素 delete p; // 回收原栈顶结点 return temp; // 返回原栈顶元素 }
三:双端顺序栈
概念
在程序中经常需要同时使用多个栈的情况,若使用顺序栈会对栈的大小难以准确估计,从而产生有栈的溢出,为了解决这个问题,让多个栈共享一个足够大的数组空间,利用栈的动态性使存储空间相互补充。
在顺序栈的共享技术中,最常用的就是两个栈共享,即双端栈。利用栈低位置不变,栈顶变化的特性。首先申请一个一维数组空间,S[M],将两个栈的栈低分别放在数组的两端,分别是0和M-1,由于是栈顶动态变化的,这样可以形成互补,使得每个栈可用的最大空间与需求有关,由此可见,两个共享栈比两个栈分别申请M/2哥空间利用率高。
typedef struct Stack { int data[max]; int top[2]; }Dqstack;
进栈及出栈代码
#include<stdio.h> #define max 5 typedef struct Stack { int data[max]; int top[2]; }Dqstack; void InitDqstack(Dqstack *s) { s->top[0]=-1; s->top[1]=max; } void Push(Dqstack *s,int a[],int k,int i) { if(s->top[0]+1==s->top[1]) { printf("The stack is full! "); return; } else { switch(i) { case 0: { for(int i=0;i<=k;i++) { s->top[0]++; s->data[s->top[0]]=a[i]; } break; } case 1: { for(int i=0;i<=k;i++) { s->top[1]--; s->data[s->top[1]]=a[i]; } break; } default: return; } printf("Successful entry into the stack! "); } } int Pop(Dqstack *s,int _i) { switch(_i) { case 0: { if(s->top[0]==-1) { printf("Stack empty! "); return -1; } else { s->top[0]--; printf("Successful leave into the stack! "); } break; } case 1: { if(s->top[1]==max-1) { printf("Stack empty! "); return -1; } else { s->top[1]++; printf("Successful leave into the stack! "); } break; } default: return -1; } } void P_rint(Dqstack *s,int _i,int k) { printf("Now data in the Stack is: "); switch(_i) { case 0: { for(int i=s->top[0];i>=0;i--) printf("%-3d",s->data[i]); break; } case 1: { for(int i=s->top[1];i<max;i++) printf("%-3d",s->data[i]); break; } default: return; } printf(" "); } int main() { int i,_i,a[max],x,k=-1,result; Dqstack s; InitDqstack(&s); printf("Please input the data (x): "); for(int i=0;i<max;i++) { scanf("%d",&x); if(x==0) break; a[i]=x; k++; } printf("Please input enter the (i) push top[0] or top[1]: "); scanf("%d",&i); Push(&s,a,k,i); printf("Please input out the (_i) pop top[0] or top[1]: "); scanf("%d",&_i); result=Pop(&s,_i); if(result==-1) return 0; P_rint(&s,_i,k); return 0; }
以上是关于顺序栈链栈双端栈的主要内容,如果未能解决你的问题,请参考以下文章
(王道408考研数据结构)第三章栈和队列-第二节:队列基本概念顺序栈和链栈基本操作