目录
1.基本概况
(1)我们之前学习了栈,栈就是先进入,后出来,后进先出,然后使用这个特性解决了括号的匹配问题;
(2)队列就是先进先出,而且是从一头进入,从另外一头出去,栈分为入栈和出栈,队列里面也是分为入队和出队两个部分;
2.队列组成
(1)队列里面的每一个数据也是有自己的next指针和val数值的,但是我们在实现这个在队尾队头插入数据的时候,这个传入这个队头的指针和队尾的指针,而且是二级指针,为什么要传递二级指针,因为我们本身传递的参数就是一个指针,通过这个指针,函数实现的时候才可以找到这个队列的头部尾部节点,我们经过这个插入和删除之后,这个形参的修改时需要同步到实参,但是如果我们传递这个一级指针,就没有办法实现这一点,因此,我们需要传递二级指针;
(2)为什么进行队尾和队头的插入和删除的时候,参数里面是两个指针,一个是头指针,一个是尾指针,插入数据的时候还需要给一个变量作为第三个参数;
(3)这个地方,为了简单起见,我们决定再去定义一个结构体,存放这个头结点和尾结点,这个时候,我们就定义了两个结构体,第一个结构体表示的是每一个节点,这个节点里面包括了这个next指针和val数值,第二个结构体里面包含这个队列的头指针和尾指针;
(4)定义了两个结构体之后,我们就可以把这个结构体作为参数进行传递,因为我们的这个结构体里面是两个一级指针,我们传递参数的时候只需要把这个结构体的指针传递进行就可以了,这个结构体里面就包含了队列的头指针和尾指针;
3.队列的实现
(1)队列的初始化
就是先去断言,然后把这个队列的头尾指针全部置为空指针,节点的个数初始化为0;
(2)队列的销毁
使用循环语句,不断的释放每一个节点,最后再让这个phead和ptail全部置空;
(3)队列的尾插
我们知道这个队列里面的数据都是从队尾进入,所以这个push也是从队尾去插入数据,我们需要手动的开辟新的节点空间;
如果这个队列本来就是空的,这个时候队列的头节点和尾结点都是newnode,否则的话,这个头结点不变,尾结点更新一下就可以了,使用if else实现这个功能;
(4)队列的头删
我们的队列里面的数据从头部出来,简称头部删除,我们需要判断这个队列里面的元素的个数,如果这个队列里面只有一个节点,这个时候ptail和phead都是指向的这个节点,我们把任意的一个空间释放掉,另外一个就会变成野指针;
因此我们进行判断,如果只有一个节点,释放完空间之后,把这个ptail和phead都置为空指针;否则就把这个next节点记录下来,删除旧的节点之后,让我们的next成为新的头结点;
(5)队列的判空
直接判断这个pq->size==0即可,如果是0,就说明这个队列里面没有数据,返回值bool就是0,有数据的话就返回的是1;
(6)队列的元素个数
pq->size就是这个队列里面的节点的个数,直接返回即可;
(7)返回头部节点
返回头部节点,pq这个队列不可以是空的,而且这个队列的头结点不可以是空的,否则我们的这个目的就无法达到;
(8)返回尾部节点
返回尾部节点,这个队列不可以是空的,而且这个队列的尾部节点不可以是空的,否则无法找到这个节点里面的val数值;
4.完整代码
(1)头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int qdatatype;
typedef struct quenenode
{
struct quenenode* next;
qdatatype val;
}qnode;
//队列的一个特点就是先进先出,后进后出
typedef struct quene
{
qnode* phead;
qnode* ptail;
int size;
}quene;
void queneinit(quene* pq);
void quenedestory(quene* pq);
void quenepush(quene* pq, qdatatype x);
qdatatype queneback(quene* pq);
qdatatype quenefront(quene* pq);
int quenesize(quene* pq);
bool queneempty(quene* pq);
(2)源文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"quene.h"
void queneinit(quene* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
void quenedestory(quene* pq)
{
assert(pq);
qnode* cur = pq->phead;
while (cur)
{
qnode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = pq->ptail = NULL;
}
void quenepush(quene* pq, qdatatype x)
{
assert(pq);
qnode* newnode = (qnode*)malloc(sizeof(qnode));
if (newnode == NULL)
{
perror("malloc fail!");
return;
}
newnode->next = NULL;
newnode->val = x;
if (pq->ptail == NULL)
{
pq->ptail = pq->phead = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
//出队列,从头部删除数据
void quenepop(quene* pq)
{
assert(pq);
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
qnode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
qdatatype queneback(quene* pq)
{
assert(pq);
assert(pq->ptail);
return pq->ptail->val;
}
qdatatype quenefront(quene* pq)
{
assert(pq);
assert(pq->phead);
return pq->phead->val;
}
int quenesize(quene* pq)
{
assert(pq);
return pq->size;
}
bool queneempty(quene* pq)
{
assert(pq);
return pq->size == 0;
}
(3)测试文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"quene.h"
void test01()
{
quene q;
queneinit(&q);
quenepush(&q, 1);
quenepush(&q, 2);
quenepush(&q, 3);
quenepush(&q, 4);
while (!queneempty(&q))
{
printf("%d ", quenefront(&q));
quenepop(&q);
}
printf("\n");
}
int main()
{
test01();
return 0;
}