链栈
讲完了栈的顺序存储结构,现在来看栈的链式存储结构,简称为链栈。
想想看,栈只是栈顶来做插入和删除操作,栈顶放在链表的头部还是尾部?
由于单链表有头指针,而栈顶指针也是必须的,所以比较好的办法是把栈顶放在单链表的头部。
都已经有了栈顶在头部了,单链表中常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。
链栈的结构代码:
/* 链栈结构 */
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode,*LinkStackPtr;
typedef struct
{
LinkStackPtr top;
int count;
}LinkStack;
链栈的操作绝大部分都和单链表相似,只是在插入删除上,特殊一些。
空栈
对于空栈,链表原定义是头指针指向空:
那么,链栈的空其实就是top=NULL的时候。
Push—进栈操作
假设,元素值为 e 的新结点是 s,top为栈顶指针,示意图如下:
/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S,SElemType e)
{
LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode));
s->data=e;
s->next=S->top; /* 把当前的栈顶元素赋值给新结点的直接后继,见图中① */
S->top=s; /* 将新的结点s赋值给栈顶指针,见图中② */
S->count++;
return OK;
}
pop—出栈操作
链栈的出栈操作,也是很简单的三句操作,假设变量 p 用来存储要删除的栈顶结点,将栈顶指针下移一位,最后释放 p 即可。
/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
Status Pop(LinkStack *S,SElemType *e)
{
LinkStackPtr p;
if(StackEmpty(*S))
return ERROR;
*e=S->top->data;
p=S->top; /* 将栈顶结点赋值给p,见图中③ */
S->top=S->top->next; /* 使得栈顶指针下移一位,指向后一结点,见图中④ */
free(p); /* 释放结点p */
S->count--;
return OK;
}