-
前言
栈的逻辑结构其实也是线性表,只不过它的插入和删除操作受限,如下图所示:
栈只有一端能够插入和删除,这端叫做栈顶;而不同操作的一端就称为栈顶。所以,后面进入栈的元素能够被优先删除,这种特性被称为后进先出(Last In First Out,LIFO)。
-
顺序栈
顺序栈,顾名思义,就是用顺序存储实现的栈,它使用一连串连续的存储单元来存储栈元素,同时加入一个指针,表明现在栈的元素个数。
2.1顺序栈的定义
顺序栈的定义如下所示:
#define MaxSize 50
typedef struct
{
Elemtype data[MaxSize];
int top;
}SqStack;
包含一个存储元素的数组和一个栈顶指针。值得注意的是,一般top为数组的下标,所以top最大取值为MaxSize-1。
2.2顺序栈的初始化
顺序栈的初始化只需要把栈顶指针设置为-1即可,表示空表:
void InitStack(SqStack &S)
{
S.top=-1;
}
2.3判断顺序栈是否为空
当顺序栈的栈顶指针为-1时,自然为空:
bool StackEmpty(SqStack S)
{
if(S.top==-1)
return true;
else
return false;
}
2.4进栈
当要输入新的元素进栈时,代码如下:
bool Push(SqStack &S, Elemtype x)
{
if(S.top==MaxSize-1)
return false;
S.data[++S.top]=x;
return true;
}
值得注意的是,数组下标内++S.top的意思是,先给top指针加一,表示栈内元素加一,然后再以加一后的下标作为插入的位置,然后在此位置插入元素x。
2.5出栈
当要删除栈顶元素时,代码如下:
bool Pop(SqStack &L,Elemtype &x)
{
if(S.top==-1)
return false;
x=S.data[S.top--];
return true;
}
同样的,S.top--的意思是先读取S.top后再对其减一。
2.6读取栈顶元素
即读取top位置的元素:
bool GetTop(SqStack &S,Elemtype &x)
{
if(S.top==-1)
return false;
x=S.data[S.top];
return true;
}
-
链栈
链栈就是用链式存储实现的栈,如果是链式存储,那么容量理论上是可以比顺序存储大很多。
3.1链栈的定义
链栈和链表一样,一个节点包括一个数据域和一个指针域,这里以带头节点的链栈作例,代码如下:
typedef struct LinkedStackNode
{
Elemtype data;
LinkedStackNode* next;
}LinkedStackNode,*LinkedStack;
3.2链栈的初始化
LinkedStack InitStack(LinkedStack &S)
{
S=(LinkedStackNode*)malloc(sizeof(LinkedStackNode));
S.next=NULL;
retuen S;
}
3.3链栈进栈
bool Push(LinkedStack &S,Elemtype x)
{
LinkedStackNode *n=(LinkedStackNode*)malloc(sizeof(LinkedStackNode));
n->data=x;
n->next=S->next;
S->next=n;
return true;
}
3.4链栈出栈
bool Pop(LinkedStack &S,Elemtype &x)
{
if(S->next=NULL)
return false;
LinkedStackNode *n=S->next;
x=n ->data;
S->next=n->next;
free(n);
return true;
}
其实链栈的出栈进栈可以类比链表的第一个节点删除和头插法建立单链表。
3.5读取栈顶元素
bool GetTop(LinkedStack &S,Elemtype &x)
{
if(S->next==NULL)
return false;
x=S->data;
return true;
}
-
共享栈
共享栈相对于顺序栈和链栈就比较啰嗦,它是利用栈底不变的特性,让两个栈共享一个一维数组的空间,如下图所示:
4.1共享栈的定义
共享栈其实就是把两个栈塞进一个数组里,定义代码如下:
#define MaxSize 20
typedef struct
{
Elemtype data[MaxSize];
int top0,top1;
}ShareStack;
4.2共享栈的初始化
初始化也很简单,就是把栈顶指针变为-1或者MaxSize即可,如下:
void InitStack(ShareStack &S)
{
S.top0=-1;
S.top1=MaxSize;
}
4.3判断共享栈是否满
如果按照上面方法定义栈顶指针,那么当共享栈满的时候,栈顶指针有一定关系,那就是top0+1=top1:
bool StackFull(ShareStack S)
{
if(S.top0+1==S.top1)
return true;
else
return false;
}
4.4进栈
4.4.1零号栈进栈
如果是0号栈进栈,那就和正常顺序栈进栈没什么区别,如下:
bool Push0(ShareStack &S,Elemtype x)
{
if(StackFull(S)==true)
return false;
S.data[++S.top0]=x;
return true;
}
4.4.2一号栈进栈
如果是1号栈进栈,那就得反过来:
bool Push1(ShareStack &S,Elemtype x)
{
if(StackFull(S)==true)
return false;
S.data[--S.top1]=x;
return true;
}
4.5出栈
4.5.1零号栈出栈
bool Pop0(ShareStack &S,Elemtype &x)
{
if(S.top0==-1)
return false;
x=S.data[S.top0--];
return true;
}
4.5.2一号栈出栈
bool Pop1(ShareStack &S,Elemtype &x)
{
if(S.top1==MaxSize)
return false;
x=S.data[S.top1++];
return true;
}