目录
1.摘要
2.引子
3.什么是栈?
4.栈的代码实现
4.1.用顺序表实现栈
4.2.头文件
4.3.接口文件
4.4.测试文件
5.参考文献
1.摘要
本文主要介绍栈的结构以及栈的代码实现。
2.引子
相必在座的军迷朋友一定不少吧,哈哈,实不相瞒,我也是一个轻武器的铁杆军迷。
如果提到手枪,那么不得不提的就是格洛克了。简洁的外观搭配强大的火力,在军用民用市场广受追捧。
那么大家是否见过往弹匣压子弹呢?对了对了,就是一发一发地把子弹压入弹仓
不对啊不对啊,我们今天不是来研究栈这个数据结构的吗?怎么扯得这么远了?
别急别急,待会你就知道为什么要讲这个例子了。
3.什么是栈?
和之前讲的顺序表和链表一样,栈也是线性表的一种,只不过,栈遵循的规则比起顺序表、链表来严格了一点
让我们给出栈的定义:栈是满足后进先出(Last in First out,LIFO)规则的线性表,只允许在固定的一端进行插入和删除操作。进行插入删除操作的一端叫做栈顶,另一端叫做栈底。
压栈操作:栈的插入操作叫做进栈/压栈/入栈,数据入栈在栈顶。
出栈操作:栈的删除操作叫做出栈。数据出栈也在栈顶。
下图清楚地展示了什么是入栈/出栈:
入栈和出栈:
多组数据的入栈和出栈:
当然了,顺便提一句,压栈操作的英文是Push,出栈操作的英文是Pop
只要牢牢记住后进先出的原则,即第一个进栈的数据最后一个才能出来,那么栈的性质就十分通透了。
还记得之前的给弹匣压弹吗?有没有一点感觉呢现在?
对了,第一发压进去的子弹最后才能射出来,最后压进去的子弹第一发就能射出来!这难道不是后进先出吗?
回顾一下开篇的那张压子弹图片,这难道不是压栈操作吗:
再来看一看子弹上膛的情景,这难道不是出栈操作吗:
后进先出!后进先出!后进先出!重要的事情说三遍!
4.栈的代码实现
4.1.用顺序表实现栈
由于栈是一类特殊的线性表,所以栈既可以用顺序表实现,也可以用链表来实现。
经过考虑,由于栈的操作通常是在栈顶完成,而通常线性表头我们认为是栈底,而线性表尾我们认为是栈顶,所以为了方便在线性表尾进行操作,本次我们采用动态开辟数组的方式来实现栈,尾部操作的时间复杂度华仅为O(1)。
当然,如果使用双向链表,也是很方便的,但是非循环单链表进行尾部操作需要遍历,时间复杂度华为O(N),不是很划算。
4.2.头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
# define INIT_NUM 4
typedef int StackDataType;
typedef struct Stack {
StackDataType* data;
size_t size;
size_t capacity;
}Stack;
void StackInit(Stack* ps);
void StackDestroy(Stack* ps);
void StackPush(Stack* ps, StackDataType x);
void StackPop(Stack* ps);
int StackEmpty(Stack* ps);
size_t StackSize(const Stack* ps);
StackDataType StackTop(const Stack* ps);
4.3.接口文件
我们尤其强调以下四个接口:
// 1.压栈
void StackPush(Stack* ps, StackDataType x);
// 2.出栈
void StackPop(Stack* ps);
// 3.判空,栈为空返回1,非空返回0
int StackEmpty(Stack* ps);
//取栈顶元素
StackDataType StackTop(const Stack* ps);
以下是接口文件的实现:
void StackBuy(Stack* ps)
{
assert(ps);
ps->capacity = ps->capacity == 0 ? INIT_NUM : 2 * ps->capacity;
StackDataType* tmp = (StackDataType*)realloc(ps->data, ps->capacity * sizeof(StackDataType));
if (tmp == NULL)
{
printf("realloc failed\n");
return;
}
ps->data = tmp;
}
void StackCheck(Stack* ps)
{
assert(ps);
if (ps->capacity == ps->size)
{
StackBuy(ps);
}
}
void StackInit(Stack* ps)
{
assert(ps);
ps->capacity = 0;
ps->size = 0;
ps->data = NULL;
StackBuy(ps);
}
void StackDestroy(Stack* ps)
{
assert(ps);
ps->capacity = 0;
ps->size = 0;
free(ps->data);
ps->data = NULL;
}
void StackPush(Stack* ps, StackDataType x)
{
assert(ps);
StackCheck(ps);
ps->data[ps->size] = x;
ps->size++;
}
void StackPrint(const Stack* ps)
{
assert(ps);
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%d ", ps->data[i]);
}
printf("\n");
}
void StackPop(Stack* ps)
{
assert(ps);
if (ps->size == 0)
return;
else
--ps->size;
}
int StackEmpty(Stack* ps)
{
return ps->size == 0;
}
size_t StackSize(const Stack* ps)
{
return ps->size;
}
StackDataType StackTop(const Stack* ps)
{
assert(ps);
assert(StackEmpty(ps));
return ps->data[ps->size - 1];
}
4.4.测试文件
Test1()
{
Stack st;
Stack* pstack = &st;
StackInit(pstack);
StackPush(pstack, 1);
StackPush(pstack, 2);
StackPush(pstack, 3);
StackPush(pstack, 4);
StackPop(pstack);
StackPop(pstack);
StackPop(pstack);
StackPop(pstack);
printf("%d\n", StackEmpty(pstack));
printf("%d\n", StackSize(pstack));
StackDestroy(pstack);
}
int main()
{
Test1();
return 0;
}