本文参考自《大话数据结构》
栈的链式存储结构及实现
对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间;而空栈,其实就是栈顶指针top=null的时候。
1.链栈的结构代码
typedef struct StackNode{
SElemType data; //数据域
struct StackNode *next; //下一个结点指针
}StackNode, *LinkStackPtr;
typedef struct LinkStack{
LinkStackPtr top; //栈顶
int count; //栈元素的个数
}LinkStack;
2.进栈操作
/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S, SElemType e){
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode)); //申请一个新结点
s->data = e; //新结点的数据域赋值
s->next = S->top; //新结点的下一个结点指向栈顶
S->top = s; //栈顶指向新结点
S->count++; //栈元素个数+1
return OK;
}
3.出栈操作
/* 若栈不为空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
Status Pop(LinkStack *S, SElemType e){
LinkStackPtr p;
if(StackEmpty(*S)){ //如果栈为空,则返回ERROR
return ERROR;
}
*e = S->top->data; //用e来返回删除的栈顶元素的值
p = S->top; //用p来暂存栈顶元素
S->top = S->top->next; //将栈顶元素指针指向原栈顶元素的下一个元素
free(p); //释放p指针所指向的内存单元
S->count--; //栈元素个数-1
return OK;
}
出栈和入栈都没有任何循环操作,时间复杂度均为O(1)。
4.对比顺序栈和链栈
- 时间复杂度都为O(1);
- 空间性能:顺序栈需要事先固定一个长度,可能会存在内存空间浪费问题,但是优势是存取时定位方便;
- 链栈要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制;
- 如果栈在使用过程中元素变化不可预料,有时很小,有时很大,最好使用链栈;
- 如果栈在使用过程中变化在可控范围内,建议使用顺序栈会好一些。
5.简单实现
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
typedef int Status;
typedef int SElemType;
typedef struct StackNode{
SElemType data;
struct StackNode* next = NULL;
}StackNode;
typedef struct LinkStack{
StackNode *top;
int count;
}LinkStack;
/* 栈空 */
bool stackEmpty(LinkStack* S){
if(S->count == 0)