链表实现栈(C语言)
总纲
- 栈结点的声明
- 栈的声明
- 栈的初始化
- 判断栈是否为空
- 入栈
- 出栈
- 获取栈顶元素
- 获取栈的大小
- 打印栈
- 栈的销毁
一. 栈结点的声明
由于存储的元素类型是任意的,所以用typedef将类型用一个变量表示
数据域存数据, 指针域存下一个结点的地址
typedef int type;
typedef struct StackNode
{
type data;
StackNode* next;
}StackNode;
二. 栈的声明
创建一个栈的结构体,其中应该包含栈顶的指针和栈的大小
typedef struct ListStack
{
int size;
StackNode* top;
}ListStack;
三. 栈的初始化
首先想一想初始化的栈是什么样子的
1. top指向空,因为此时没有任何元素
2. size为0,表示此时元素个数为0
void init(ListStack* stk)
{
stk->size = 0;
stk->top = NULL;
}
四. 判断栈是否为空
判断栈是否为空可以看size是不是0,也可以看top指不指向NULL
bool isEmpty(ListStack* stk)
{
return stk->size == 0;
}
五. 入栈
入栈时要向内存申请一个结点的空间,并判断是否成功
入栈时不需要要看栈是否为空,只要让node指向top的后继结点就行了
注意这里要不要判断栈是否为空和要不要改变头结点无关,因为根据栈先入先出的特点而采用头插法,不管怎样都会改变头结点
void Push(ListStack* stk, type x)
{
StackNode* node = (StackNode*)malloc(sizeof(StackNode));
if (node == NULL)
{
printf("MallocError\n");
exit(1);
}
node->data = x;
node->next = stk->top;
stk->top = node;
stk->size++;
}
六. 出栈
出栈时让top变成它的后继结点就相当于删除了栈顶元素
不要忘记判断栈是否为空
因为每一个结点都是申请的,所以不要忘记释放空间
type Pop(ListStack* stk)
{
StackNode* tmp = stk->top;
type ret = tmp->data;
stk->top = stk->top->next;
free(tmp);
tmp = NULL;
return ret;
}
七. 获取栈顶元素
不要忘记判断栈是否为空
type Top(ListStack* stk)
{
if (stk->size == 0)
{
exit(0);
}
return stk->top->data;
}
八. 获取栈的大小
int capacity(ListStack* stk)
{
return stk->size;
}
九. 打印栈
一共有三种方式打印
- 顺序打印
void print(StackNode* top)
{
StackNode* start = top;
while(start != NULL)
{
printf("%d ", start->data);
start = start->next;
}
}
- 递归顺序打印
void recursion_print(StackNode* top)
{
StackNode* start = top;
if (start == NULL)
{
return;
}
else
{
printf("%d ", start->data);
recursion_print(start->next);
}
}
- 递归逆序打印
void reverse_recursion_print(StackNode* top)
{
StackNode* start = top;
if (start == NULL)
{
return;
}
else
{
reverse_recursion_print(start->next);
printf("%d ", start->data);
}
}
十. 栈的销毁
要把每一个结点都释放并置空
void destroy(ListStack* stk)
{
while(stk->top != NULL)
{
StackNode* tmp = stk->top;
stk->top = stk->top->next;
free(tmp);
tmp = NULL;
}
stk->size = 0;
}