栈和队列是两种特殊的线性表,它们的逻辑结构和线性表相同,只是其运算规则较线性表有更多的限制,故又称它们为运算受限的线性表。栈和队列被广泛应用于各种程序设计中。
栈的概念
- 栈(Stack):是限制在表的一端进行插入和删除操作的线性表。又称为后进先出LIFO(Last In First Out)或先进后出FILO(First In Last Out)线性表。
- 栈顶(Top):允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
- 栈底(Bottom):是固定端,又称为表头。
- 空栈:当表中没有元素时称为空栈。
栈的抽象数据类型定义
- ADT Stack
- {
- 数据对象:D={ ai|ai∈ElemSet, i=1,2,…,n,n≥0}
- 数据关系:R={<ai-1,ai>|ai-1,ai∈D, i=2,3,…,n}
- 基本操作:初始化、进栈、出栈、取栈顶元素等
- }
栈的顺序存储表示
栈的顺序存储结构简称为顺序栈,和线性表相类似,用一维数组来存储栈。根据数组是否可以根据需要增大,又可分为静态顺序栈和动态顺序栈。静态顺序栈实现简单,但不能根据需要增大栈的存储空间;动态顺序栈可以根据需要增大栈的存储空间,但实现稍为复杂。
栈的动态顺序存储表示
采用动态一维数组来存储栈。所谓动态,指的是栈的大小可以根据需要增加。
- 用bottom表示栈底指针,栈底固定不变的;栈顶则随着进栈和退栈操作而变化。用top(称为栈顶指针)指示当前栈顶位置。
- 用top=bottom作为栈空的标记,每次top指向栈顶数组中的下一个存储位置。
- 结点进栈:首先将数据元素保存到栈顶(top所指的当前位置),然后执行top加1,使top指向栈顶的下一个存储位置;
- 结点出栈:首先执行top减1,使top指向栈顶元素的存储位置,然后将栈顶元素取出。
- //栈的类型定义
- #define STACK_SIZE 100 /* 栈初始向量大小*/
- #define STACKINCREMENT 10 /* 存储空间分配增量 */
- typedef int ElemType ;
- typedef struct sqstack
- {
- ElemType *bottom; /* 栈不存在时值为NULL */
- ElemType *top; /* 栈顶指针 */
- int stacksize ; /* 当前已分配空间,以元素为单位 */
- }SqStack ;
- //栈的初始化
- int Init_Stack(void)
- {
- SqStack S ;
- S.bottom=(ElemType*)malloc(STACK_SIZE *sizeof(ElemType));
- if (! S.bottom) return ERROR;
- S.top=S.bottom ; /* 栈空时栈顶和栈底指针相同 */
- S.stacksize=STACK_SIZE;
- return OK ;
- }
- //压栈(元素进栈)
- int push(SqStack S , ElemType e)
- {
- if (S.top-S.bottom>=S.stacksize-1)
- {
- S.bottom=(ElemType *)realloc((S.STACKINCREMENT+STACK_SIZE)*sizeof(ElemType)); /* 栈满,追加存储空 间 */
- if (! S.bottom) return ERROR;
- S.top=S.bottom+S. stacksize ;
- S. stacksize+=STACKINCREMENT ;
- }
- *S.top=e;
- S.top++ ; /* 栈顶指针加1,e成为新的栈顶 */
- return OK;
- }
- //弹栈(元素出栈)
- int pop( SqStack S, ElemType *e )/*弹出栈顶元素*/
- {
- if ( S.top== S.bottom )
- return ERROR ; /* 栈空,返回失败标志*/
- S.top-- ;
- e=*S. top ;
- return OK ;
- }
栈的静态顺序存储表示
采用静态一维数组来存储栈。
- 栈底固定不变的;栈顶则随着进栈和退栈操作而变化,用一个整型变量top(称为栈顶指针)来指示当前栈顶位置。
- 用top=0表示栈空的初始状态,每次top指向栈顶在数组中的存储位置。
- 结点进栈:首先执行top加1,使top指向新的栈顶位置,然后将数据元素保存到栈顶(top所指的当前位置)。
- 结点出栈:首先把top指向的栈顶元素取出,然后执行top减1,使top指向新的栈顶位置。
若栈的数组有Maxsize个元素,则top=Maxsize-1时栈满。
- //基本操作的实现
- //栈的类型定义
- # define MAX_STACK_SIZE 100 /* 栈向量大小 */
- typedef int ElemType ;
- typedef struct sqstack
- {
- ElemType stack_array[MAX_STACK_SIZE] ;
- int top;
- }SqStack ;
- //栈的初始化
- SqStack Init_Stack(void)
- {
- SqStack S ;
- S.bottom=S.top=0 ;
- return(S) ;
- }
- //压栈(元素进栈)
- Status push(SqStack S , ElemType e)/* 使数据元素e进栈成为新的栈顶 */
- {
- if (S.top==MAX_STACK_SIZE-1)
- return ERROR; /* 栈满,返回错误标志*/
- S.top++ ; /* 栈顶指针加1 */
- S.stack_array[S.top]=e ; /* e成为新的栈顶 */
- return OK; /* 压栈成功 */
- }
- //弹栈(元素出栈)
- Status pop( SqStack S, ElemType *e )/*弹出栈顶元素*/
- {
- if ( S.top==0 )
- return ERROR ; /* 栈空,返回错误标志*/
- *e=S.stack_array[S.top] ;
- S.top-- ;
- return OK ;
- }
存储栈的链式表示
栈的链式存储结构称为链栈,是运算受限的单链表。其插入和删除操作只能在表头位置上进行。因此,链栈没有必要像单链表那样附加头结点,栈顶指针top就是链表的头指针。
- //链栈的结点类型说明如下:
- typedef struct Stack_Node
- {
- ElemType data ;
- struct Stack_Node *next ;
- }Stack_Node ;
- //链栈基本操作的实现--链栈基本操作的实现
- //栈的初始化
- Stack_Node *Init_Link_Stack(void)
- {
- Stack_Node *top ;
- top=(Stack_Node*)malloc(sizeof(Stack_Node )) ;
- top->next=NULL ;
- return(top) ;
- }
- //压栈(元素进栈)
- Status push(Stack_Node *top , ElemType e)
- {
- Stack_Node *p ;
- p=(Stack_Node *)malloc(sizeof(Stack_Node)) ;
- if (!p) return ERROR; /* 申请新结点失败,返回错误标志 */
- p->data=e ;
- p->next=top->next ;
- top->next=p ; /* 钩链 */
- return OK;
- }
- //弹栈(元素出栈)
- Status pop(Stack_Node *top , ElemType *e)/* 将栈顶元素出栈 */
- {
- Stack_Node *p ;
- ElemType e ;
- if (top->next==NULL )
- return ERROR ; /* 栈空,返回错误标志 */
- p=top->next ;
- e=p->data ; /* 取栈顶元 素 */
- top->next=p->next ; /* 修改栈顶指针 */
- free(p) ;
- return OK;
- }