一 栈:
1.1:什么是栈
栈是一种数据结构,它遵循"后进先出"的原则。栈可以看作是一种特殊的线性表,只能在表的一端进行插入和删除操作,该端被称为栈顶,另一端被称为栈底。
在栈中,最后插入的元素首先被访问和删除,而最先插入的元素最后被访问和删除。这就类似于我们平时堆放书籍或者盘子的方式,最后放上去的会最先被拿走。
1.2:栈的实现
栈的基本操作便是入栈以及出栈
栈我们可以通过之前线性表的方式,只需要将入栈视作头插,出栈视作头删即可实现。
同时我们也可以用数组的方式来实现栈:
定义栈:
其中数组我们进行动态开辟,定义栈顶的位置为top,数组容量为capacity;
初始化栈:
由于top需要指向栈顶的元素,而每次入栈元素后top就会+1,因此我们直接最开始初始化为-1这样每次top+1后入栈元素后top就指向了栈顶(当然,top=0也有top=0的写法)。
入栈:
在这里首先我们判断数组是否有足够的空间(下标top+1=容量capacity就没有多余空间此时需要进行扩容操作) ,接着在++top(新的栈顶位置)把x入栈。
出栈:
在这里我们只需要让top--就是得到了新的栈顶,至于原栈顶我们不需要做特殊处理因为我们访问不到并且下次会覆盖掉。
获取栈顶元素:
top指向的位置为栈顶元素,返回即可。
获取数据个数:
top为栈顶元素下标,+1的值即为栈的元素个数。
栈的判空:
当栈顶位置为-1即为空。
栈的销毁:
二 对列:
2.1:什么是队列:
队列和栈一样是一种数据结构,它遵循"先进先出"的原则。队列可以看作是一种特殊的线性表,只能在表的一端进行插入操作(入队),在另一端进行删除操作(出队)。
队列类似于现实生活中排队的情形,先到先服务。最先进入队列的元素将会最先被处理,而最后进入队列的元素将会最后被处理。
2.2 队列的实现:
定义队列:
在这里我们用链式结构来表示队列,队列的结构包括了指向头节点的指针phead,指向为节点的指针ptail以及队列的大小size,头节点和尾节点都包括自身数据和指向下一个节点的指针。由于队列的特性,我们在这链式结构上入队列即尾插,出队列即头删。
初始化队列:
入队列 :
首先如果phead为空即队列为空我们创建一个节点储存数据后给队列,此时队列只有一个节点,所以头节点尾部节点都指向新节点。
如果不是空队列就在原队列进行尾插即可。
相应的入队列后size++;
出队列:
出队列即进行尾删操作,队列不能为空,删除即释放头节点,让头节点指向next,size--。
获取队列头元素:
即为头节点。
获取队列尾元素:
即为为节点。
获取队列元素个数:
因为我们定义了size来储存元素个数就会很方便不需要再去遍历一遍。
队列判空:
size为0即为空 。
队列的销毁:
free掉链表的节点。
三 循环队列
循环队列是一种特殊的队列数据结构。它通过使用循环数组来实现队列的功能,解决了普通队列在出队操作后无法再利用已出队的空间的问题。
循环队列的特点是队列的头尾相连,形成一个循环。当队列满时,新的元素可以从队列的开头重新插入,实现循环利用。这样一来,循环队列可以更有效地利用内存空间。
循环队列的实现:
设计循环队列:
https://leetcode.cn/problems/design-circular-queue/
因为循环队列的数据元素是固定的我们就直接采用数组的方式去实现。
如果我们的循环队列需要有4个空间存放数据我们就扩容五个空间去执行push操作,其中总有一个空间不会使用
最开始的情况:
当我们push四个元素时
如图当我们push四个元素时ptail的前一个位置为队列的尾。
也就是当ptail的下一个位置为phead时我们的队列就是满队列不能插入。
如果继续插入我们就应该把phead的位置的值置空后phead走到下一个位置然后在ptail位置插入元素在走到下一个位置。
根据这样的逻辑我们就可以轻松的完成设计循环队列的这道题。
设计代码:
typedef struct {
int*a;
int dip;
int top;
int size;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue*quene=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
int *numa=(int*)malloc((k+1)*sizeof(int));
quene->a=numa;
quene->dip=0;
quene->top=0;
quene->size=k;
return quene;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if((obj->dip+1)%(obj->size+1)==obj->top)return false;
else
{
obj->a[obj->dip]=value;
if(obj->dip<obj->size)obj->dip++;
else obj->dip=0;
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(obj->top==obj->dip)return false;
else
{
obj->a[obj->top]=0;
if(obj->top==obj->size)obj->top=0;
else obj->top++;
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj) {
// printf("%d",obj->top);
if(obj->top==obj->dip)return -1;
else return obj->a[obj->top];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->top==obj->dip)return -1;
else
{
printf("%d ",obj->dip);
if(obj->dip==0)return obj->a[obj->size];
else return obj->a[obj->dip-1];
}
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->top==obj->dip)return true;
else return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
int fu=obj->dip;
if(fu<obj->size)fu++;
else fu=0;
if(fu==obj->top)return true;
else return false;
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
最后关于栈和队列的一些基本知识就差不多了,掌握这些我们还可以实现用队列实现栈,用栈实现队列之类的题目。