栈的链式存储
在讨论完栈的顺序结构后我们需要了解栈的链式结构,简称为链栈
在单链表中有头指针,而栈也存在栈顶指针,所以我们可以将这两者合二为一,将头指针作为栈的栈顶指针,栈顶指针将作为整个单链表的起始位置,所以链栈不需要头结点了
链栈的一大特点就是不会存在没有栈空间的情况,除非内存中已经没有可以使用的空间了,和顺序栈需要提前定义好数组相比灵活许多,对于空栈来说,top=NULL;
链栈的结构代码如下:
typedef struct StackNode{ //栈链结点
SElemType data;
struct StackNode *next;
} StackNode, *LinkStackPtr;
typedef struct LinkStack{ //定义栈顶结点
LinkStackPtr top;
int count;
};
因为在链栈中栈顶元素指针可以标识整条链表,所以我们将栈顶元素指针封装到一个结构体中,将这个结构体作为参数传入到Push函数中,即相当于将整条链栈传入Push函数中,这个结构体中还存在一个整形变量count,负责记录链栈中元素的个数
在将栈结构定义完成后我们需要编写栈的入栈操作的代码实现:
Status Push(LinkStack *S, SElemType e){
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
s->data = e;
s->next = S->top;
S->top = s;
S->count++;
return OK;
}
在进栈后我们继续编写出栈操作的代码实现:
Status Pop(LinkStack *S, SElemType *e){
LinkStackPtr p;
if(StackEmpty(*S)){
return ERROR;
}
*e = S->top->data;
p = S->top;
S->top = S->top->next;
free(p);
S->count--;
return OK;
}
出栈操作和我们单链表的删除结点类似,我们需要获得待删除结点的地址后将该结点删除,之后使栈顶指针下移,并且栈顶结点结构体中的count自减1
在上面的出栈操作中我们使用到了StackEmpty
函数,这个函数的代码实现也非常简单,我们只需要判断栈顶结点的top
是否为空,因为在链栈中没有头结点,没有多余结点,当链栈为空后,top
只能为NULL;所以我么可以通过对top的值进行判断来确定我们的栈是否为空,为了便于读者理解我会在后续添加一些图解
在讲解完栈后,本来应该讲解栈的更深层次的应用比如递归和后缀表达式,但是因为我才疏学浅,需要后续知识的补充后在能将这篇博客编写完成,敬请期待