栈
栈本身也是一种线性表,只是它只允许在一端进行插入和删除,栈结构的元素满足先进后出(LIFO)的特征。线性表本身分为顺序表和链表,所以栈也分为顺序栈和链栈。
1.顺序栈
顺序表声明的时候需要指明顺序表的最大容量,同样,顺序栈也需要。
通常习惯的做法是以top=0表示空栈(在《王道数据结构》中以top=-1表示,在严蔚敏老师的《数据结构中》是以top=0表示空栈)鉴于C语言的下标从0开始,则当以C语言做描述语言时,如此设定会带来很大的不便,另一方面,栈在使用的过程中,所需要的空间的大小很难估计,因此,一般来说在初始化栈的时候,不应限定最大容量,一个较为合理的做法是:先为栈分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐步扩大,为此可设定两个常亮STACK_INIT_MAXXIZE(存储空间的初始分配量)和STACK_INCREMENT(存储空间分配增量)
顺序栈图示(栈顶指针始终指向栈顶元素的下一个位置)
顺序栈结构体
#define maxsize 50
typedrf struct{
ElemType *base; //栈底指针
ElemType *top; //栈顶指针
int stacksize; //栈的容量
}Sqstack;
初始化栈
int STACK_INIT_SIZE; //初始化栈的时候分配的空间数,需要给一个初始值
bool InitStack(Sqstack &s){
s.base=(Sqstack *)malloc(sizeof(Sqstack)*STACK_INIT_SIZE); //分配内存空间
if(!s.base) //分配失败
retuen false;
s.top=s.base; //栈为空时,栈应满足栈底和栈顶指针指向同一位置
s.stacksize=STACK_INIT_SIZE; //此时栈的容量就是初始化的空间数
retuen true;
}
取栈顶元素:
bool GetTop(Sqstack s,Elemtype &x){
if(s.top==s.base) //栈为空
retuen false;
e=*(s.top-1); //栈的栈顶指针始终处于栈顶元素的下一个位置
retuen true;
}
入栈:
int STACKINCREMENT; //扩充栈空间是的一个扩充量,需要给一个初始值
bool Push(Sqstack &s,ElemType e){
if(s.top-s.base>s.stacksize||s.top==s.base){ //空间不足
s.base=(ElemType *)ralloc(s.base,(s.stacksize+STACKINCREMENT)*sizeof(Sqstack))
//扩充STACKINCREMENT个空间
if(!s.base)
return false;
s.top=s.base+s.stacksize; //改变栈顶指针的位置到初始化最大值位置
s.stacksize+=STACKINCREMENT; //栈的容量在原基础上增加了STACKINCREMENT个空间
}
*s.top++=e; //元素先入栈,再加指针
return true;
}
出栈:
bool pop(Sqstack &s,ElemType &e){
if(s.top==s.base) //若为空栈,则直接退出
return false;
e=*--s.top; //先减指针,再减元素
return true;
}
链栈:
采用链式存储的栈,链栈不存在栈满上溢的情况,采用单链表的形式实现,并规定所有的操作都是在单链表的表头进行,链栈没有头结点。
链栈的结构体:
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*Linklist;
入栈:链表头插法
出栈:删除链表的第一个节点