各部分的解释已经以注释形式写于代码中。
1.说明
链栈实际上与单链表极为相似,区别主要在于判断条件以及链栈的操作只能在表头进行,即就是将单链表的操作固定在了表头。此处实现的是不带头结点的链栈,与带头结点的主要差别在于带头结点的链栈栈顶指针指向以及条件判断方面。实际上,相比于单链表带头结点对于不带头结点的优势,链栈由于都是在表头进行操作,所以带头结点链表的统一操作的优势便难以表现出来了。综上,带头结点的链栈实现其实与带头结点单链表相差不大,此处便不进行实现了。
2.基本操作
2.1 结构体构造
// 不带头结点
typedef struct LinkNode {
int data; // 数据域
struct LinkNode *next; // 指针域
} LSNode, *LinkStack; // 栈类型定义
2.2 初始化
// 初始化
void InitStack(LinkStack &S) {
// 此为不带头结点的栈,与单链表相似,初始将栈顶指针指向NULL即可
S = NULL;
}
2.3 判空
// 判空
bool Empty(LinkStack S) {
// 栈为空的条件即栈顶指针指向NULL
if(S == NULL) {
return true;
}
return false;
}
2.4 入栈
// 入栈操作
// 由于栈只能从一端操作,所以每次都应该是从栈顶入栈
bool Push(LinkStack &S, int e) {
// 申请分配空间
LSNode *s = (LSNode*)malloc(sizeof(LSNode));
// 内存分配失败的情况
if(s == NULL) {
return false;
}
s->data = e;
// 由于每次都是从栈顶指针处插入,所以无需特殊处理
// 令s指向S之前指向的地址
s->next = S;
// 使头指针指向s
S = s;
return true;
}
2.5 出栈
// 出栈操作
// 类似于单链表的删除操作,不过只能在栈顶进行出栈
bool Pop(LinkStack &S, int &e) {
// 如果是空栈,则不可进行出栈操作
if(S == NULL) {
return false;
}
// 出栈结点即为栈顶指针指向的结点
// 将出栈结点值赋给e
e = S->data;
// 临时结点,用于之后释放空间
LSNode* p = S;
// 使头指针指向下一个结点
S = S->next;
// 释放空间
free(p);
return true;
}
2.6 获取栈顶元素
// 获取栈顶元素
bool GetTop(LinkStack S, int &e) {
// 栈为空的情况
if(S == NULL) {
return false;
}
e = S->data;
return true;
}
2.7 输出栈中所有元素
// 输出栈中所有元素
// 由于栈只能从一端进行操作,所以想要输出所有元素,就必须要将所有元素弹出并输出
void PrintStack(LinkStack S) {
if(Empty(S)) {
printf("the stack is empty!");
}
while(!Empty(S)) {
int x;
Pop(S, x);
printf("pop:%d\n", x);
}
}
3.完整代码
#include<stdio.h>
#include<stdlib.h>
// 不带头结点
typedef struct LinkNode {
int data; // 数据域
struct LinkNode *next; // 指针域
} LSNode, *LinkStack; // 栈类型定义
// 初始化
void InitStack(LinkStack &S) {
// 此为不带头结点的栈,与单链表相似,初始将栈顶指针指向NULL即可
S = NULL;
}
// 判空
bool Empty(LinkStack S) {
// 栈为空的条件即栈顶指针指向NULL
if(S == NULL) {
return true;
}
return false;
}
// 入栈操作
// 由于栈只能从一端操作,所以每次都应该是从栈顶入栈
bool Push(LinkStack &S, int e) {
// 申请分配空间
LSNode *s = (LSNode*)malloc(sizeof(LSNode));
// 内存分配失败的情况
if(s == NULL) {
return false;
}
s->data = e;
// 由于每次都是从栈顶指针处插入,所以无需特殊处理
// 令s指向S之前指向的地址
s->next = S;
// 使头指针指向s
S = s;
return true;
}
// 出栈操作
// 类似于单链表的删除操作,不过只能在栈顶进行出栈
bool Pop(LinkStack &S, int &e) {
// 如果是空栈,则不可进行出栈操作
if(S == NULL) {
return false;
}
// 出栈结点即为栈顶指针指向的结点
// 将出栈结点值赋给e
e = S->data;
// 临时结点,用于之后释放空间
LSNode* p = S;
// 使头指针指向下一个结点
S = S->next;
// 释放空间
free(p);
return true;
}
// 获取栈顶元素
bool GetTop(LinkStack S, int &e) {
// 栈为空的情况
if(S == NULL) {
return false;
}
e = S->data;
return true;
}
// 输出栈中所有元素
// 由于栈只能从一端进行操作,所以想要输出所有元素,就必须要将所有元素弹出并输出
void PrintStack(LinkStack S) {
if(Empty(S)) {
printf("the stack is empty!");
}
while(!Empty(S)) {
int x;
Pop(S, x);
printf("pop:%d\n", x);
}
}
int main() {
LinkStack S;
InitStack(S);
int x;
Push(S, 3);
GetTop(S, x);
printf("push:%d\n", x);
Push(S, 5);
GetTop(S, x);
printf("push:%d\n", x);
Push(S, 7);
GetTop(S, x);
printf("push:%d\n", x);
PrintStack(S);
}