栈的定义
栈(Stack)是一种遵循后进先出(Last In First Out,LIFO)原则的数据结构。它的操作主要限制在数据结构的一端,称为栈顶(Top)。
压栈:栈的插入操作叫进栈\压栈\入栈,入数据在栈顶 出栈:栈的删除操作叫做出栈,出数据也在栈顶

基本特点
基本操作
适用场景
相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小,而链表尾插每次都需要申请空间创建新的节点。
下面我们就用数组实现个动态栈。
typedef int STDataType;
typedef struct Stack
{
STDataType* arr;
int top; //堆顶
int capacity; //容量(能容纳数据个数的最大数量)
}ST;初始化
//初始化
void STInit(ST* pst)
{
assert(pst);
pst->arr = NULL;
//指向栈顶数据的下一个位置
pst->capacity = pst->top = 0;
//指向栈顶数据
//pst->top = -1
}注意这里的top的指向,是指向堆顶数据的下一个位置,所以top也可以代表栈的数据个数。

入栈
//入栈
void STPush(ST* pst, STDataType x)
{
assert(pst);
//扩容
if (pst->capacity == pst->top)
{
int newcapacity = (pst->capacity == 0) ? 4 : 2 * pst->capacity;
STDataType* tep = (STDataType*)realloc(pst->arr, newcapacity * sizeof(STDataType));
if (tep == NULL)
{
perror("realloc");
return;
}
pst->arr = tep;
pst->capacity = newcapacity;
}
pst->arr[pst->top] = x;
pst->top++;
}这里的扩容需要注意,当pst->capacity == pst->top时,说明栈空间已经满了,需要扩容,一般是扩容2倍。
详细解释可以看数据结构——顺序表-CSDN博客中CheckCapacity函数的解释。
解决完扩容问题后,直接再top位置插入数据,并更新top就可以了。
出栈
移除栈顶元素,只需让top减减就行了。
注意判断栈不为空(top > 0)就可以了。
// 出栈
void STPop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
pst->top--;
}取栈顶数据
top指向栈顶数据的下一位置,返回top-1的数据就行了。
还是要注意栈不为空。
//取栈顶数据
STDataType STTop(ST* pst)
{
assert(pst);
assert(pst->top > 0);
return pst->arr[pst->top - 1];
}判空
看的是数据个数为不为0(top == 0),不是看容量(capacity)
//判空 看的是数据个数为不为0,不是看容量
bool STEmpty(ST* pst)
{
assert(pst);
return (pst->top == 0);
}获取栈的数据个数
top就是栈的数据个数,返回就好了。
//获取数据个数
int STSize(ST* pst)
{
assert(pst);
return (pst->top);
}销毁栈
用free释放掉申请的空间,然后把top和capacity置0就行了。
//销毁
void STDestroy(ST* pst)
{
assert(pst);
free(pst->arr);
pst->arr = NULL;
pst->capacity = pst->top = 0;
}队列的定义
队列(Queue)是一种遵循先进先出(First In First Out,FIFO)原则的线性数据结构。它在一端添加元素,在另一端移除元素。

基本特点
基本操作
适用场景
队列的实现使用链表结构比较好,因为涉及到头插头删,使用数组有数据挪动,效率较为低下。
下面我们就用链表去实现队列。
队列的节点和队列结构
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType val;
}QNode;
typedef struct Queue
{
QNode* phead; //队列的头节点
QNode* ptail; //队列的尾节点
int size; //队列的数据个数
}Queue;初始化
把phead和ptail置空,size置0即可。
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}插入数据到队尾(入队列)
创建一个新节点,然后尾插就行。
注意判断队列为空的情况就可以了。
// 队尾插入
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
//创建一个新节点,赋值x
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->next = NULL;
newnode->val = x;
//判断链表为空的情况
if (pq->phead == NULL)
{
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
//更新size
pq->size++;
}删除队头的元素(出队列)
删除队列头节点,跟链表的删除基本一模一样。
注意判断队列元素不为0,以及元素个数为1的情况。
// 队头删除
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->size != 0);
//判断是不是一个节点,特殊处理
if (pq->size == 1)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
//更新size
pq->size--;
}取队头队尾的数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}队列数据个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}队列的判空
判断队列的数据个数为不为0就行了,或者判断phead为不为空也可以。
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}销毁队列
遍历队列,逐个销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* del = cur;
cur = cur->next;
free(del);
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}拜拜,下期再见😏
摸鱼ing😴✨🎞
