栈
一、栈的定义
栈作为一种限定性线性表,是将线性表的插入和删除操作限制在仅在表的一端进行,通常将表中允许进行插入、删除操作的一端称为栈顶(Top),因此栈顶的当前位置是动态变化的,它由一个称为栈顶指针的位置指示器来指示。同时,表的另一端称为栈底(Bottom)。当栈中没有元素时称为空栈。栈的插入操作被形象的称为进栈或入栈,删除操作称为出栈或退栈。栈的修改是按先进后出的原则进行的。
二、栈的表示与实现
栈作为一种特殊的线性表,在计算机中主要有两种基本的存储结构:顺序存储结构和链式存储结构。我们简称顺序存储的栈为顺序栈,链式存储的栈为链栈。
1.顺序栈
顺序栈是用顺序存储结构实现的栈,即利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时由于栈操作的特殊性,还必须附设一个位置指针top(栈顶指针)来动态地指示栈顶元素在栈中的位置。通常以 top=-1 表示空栈。
顺序表的存储结构可以用C语言中的一维数组来表示,定义如下:
#define Stack_Size 50
typedef struct
{
StackElementType elem[Stack_Size];
int top;
}SeqStack;
顺序栈的进栈和出栈过程如图:
顺序栈基本操作有初始化、进栈、出栈、读栈顶元素,相应算法如下所示:
(1) 初始化顺序栈
void InitStack(SeqStack *S)
{
S->top = -1;
}
(2) 进栈
进栈时,首先判断当前栈是否已满,如果栈已满,还要进栈就会发生上溢。
int Push(SeqStack * S,StackElementType x)
{
if(S->top==Stack_Size-1) return(FALSE);
S->top++;
S->elem[S->top]=x;
return(TRUE);
}
(3)出栈
出栈时,首先判断栈是否为空,如果栈空,还要出栈就会发生下溢。
int Pop(SeqStack * S,StackElementTypa * x)
{
if(S->top==-1)
return(FALSE);
else
{
* x = S->elem[S_>top];
S->top--;
return(TRUE);
}
}
(4) 读栈顶元素
int GetTop(SeqStack * S,StackElementType * x)
{
if(S->top==-1)
return(FALSE);
else
{
*x=S->elem[S->top];
return(TRUE);
}
}
注意:在实现GetTop操作时,也可以将参数说明 SeqStack * S 改为 SeqStack S,也就是将传地址方式改为传值方式。传值比传地址容易理解,但是传地址比传值更节省时间和空间。
2.链栈
链栈即采用链表作为存储结构实现的栈.为了便于操作,这里采用带表头结点的单链表实现栈。由于栈的插入和删除操作仅限于表头位置进行,所以链表的表头指针就作为栈顶指针,如图所示:
在图中,top 为栈顶指针,始终指向当前栈顶元素前面的头结点。若top->next==NULL,则代表栈空。采用链栈不必预先估计链栈的最大容量,只要系统有可用空间,链栈就不会出现溢出。采用链栈时,栈的各种基本操作的实现与单链表的操作类似,对于链栈,在使用完毕时,应该释放相应空间。
链栈的结构可用C语言定义如下:
typedef struct node
{
StackElementType data;
struct node * next;
}LinkStackNode;
typedef LinkStackNode * LinkStack;
(1)链栈进栈操作
int Push(LinkStack top,StackElementNode x)
{
LinkStackNode * temp;
temp = (LinkStackNode *)malloc(sizeof(LinkStackNode));
if(temp==NULL)
{
return(FALSE);
}
temp->next=top->next;
top->next=temp;
return(TRUE);
}
(2)出栈操作
int Pop(LinkStack top,StackElementType * x)
{
LinkStackNode * temp;
temp=top->next;
if(temp==NULL)
return(FALSE);
top->next=temp->next;
*x = temp->data;
free(temp);
return(TRUE);
}