一、前言
今天介绍一下栈和堆
栈:是一种特殊的线性表,只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶。另一段为栈底
栈的数据遵守后进先出LIFO(last in first out)的原则
压栈:栈的插入操作叫做进栈/压栈,如数据在栈顶
出栈:栈的删除操作叫出栈,出数据也在栈顶
这里有很多人问栈和队列属于线性结构吗?可以用链表实现吗?
答案是肯定的,两者都可实现栈和队列,数据结构需要适配不同的应用场景。而顺序表和链表没有说哪个最好,都各有千秋。
顺序表在内存中是连续存储的,密度高,但是空间受限。
链式结构不受限于空间,随意扩容,但是存储是不连续的,密度低
堆:只允许在一端进行插入操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出First in first out
入队列:进行插入操作的一端成为队尾
出队列:进行删除操作的一端成为队头
栈和队列的出入顺序区别:
而队列,一种入队顺序,一种出队顺序
举个例子:
有的题目会问一个栈的入栈序列为ABCDE,出栈序列可能是什么呢?
可能是ABCDE,因为A先进,然后A出,B进B出,依次类推
可能是ABC入,然后CBA出,DE再进,ED出
但不可能是ECDBA,因为E先出,说明所有元素都已入栈,那么不可能是C先出而是D先出
典型应用场景:
- 队列实际中要保证公平排队的地方都可以用他,如抽号机
- 广度优先遍历
二、堆(stack)
1. 整体设计框架
还是和之前一样分为三个文件,而不是写在一个main函数里面,这样可读性更高,便于调试
main.c 专门用于函数调用、调试
stack.h 只用于函数声明
stack.c 用于函数实现
2. 函数实现
这里我们用数组进行数据存储
2.1 head File
我们先来看一下头文件的架构以及需要实现的函数功能
typedef int STDatatype;
typedef struct Stack{
STDatatype* a;
int top; //栈顶 , 类似于size
int capacity;
}ST;
void StackInit(ST* ps);
void StackDestory(ST* ps);
void StackPush(ST* ps, STDatatype x);
void StackPop(ST* ps);
bool StackEmpty(ST* ps);
int StackSize(ST* ps);
STDatatype StackTop(ST* ps); //取栈顶的数值
这里的STDataType是便于后期全局修改数据类型
Stack数据结构里有三个成员,第一个成员a为动态数组,后续进行空间开辟,top是指stack中的栈顶也就是数组的最后一个值,capacity为数组的总容量
2.2 StackInit
void StackInit(ST* ps){
assert(ps); //先断言,给的结构体是否为空,是空那就不用玩了,因此这里避免用户使用误传NULL
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
2.3 StackDestory
如果a数组不为空,free整个数组,并将数组a置空
void StackDestory(ST* ps){
assert(ps);
if(ps->a){
free(ps->a);
}
ps->a = NULL;
ps->top = 0;