绪论
任其事必图其效;欲责其效,必尽其方。——欧阳修;本篇文章主要写的是什么是队列、以及队列是由什么组成的和这些组成接口的代码实现过程。(大多细节的实现过程以注释的方式展示请注意查看)
话不多说安全带系好,发车啦(建议电脑观看)。
附:红色,部分为重点部分;蓝颜色为需要记忆的部分(不是死记硬背哈,多敲);黑色加粗或者其余颜色为次重点;黑色为描述需要
目录
队列
1.队列的实现编辑
1.1队列的结构
1.2队列的初始化
1.3将数据放进队列中
1.4删除数据
1.5查看队列中是否有数据
1.6查看队列中的头尾数据
1.7查看队列中有几个元素
1.8队列的摧毁
2.队列的实现代码
队列
知识点:
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾 、出队列:进行删除操作的一端称为队头
细节:
队列的基本结构框架:同样队列也是既能由顺序表也能由链表来实现的,下面将用链表来实现(因为链表相较于顺序表来说,其头删的效率比较高)
- 队列的结构
- 指向链表头的指针
- 指向链表尾的指针
- 记录链表元素个数的变量
- 队列所要实现的功能
- 队列的初始化
- 队列的摧毁
- 放入数据
- 删除数据
- 查看队列是否为空
- 获取头部、尾部的数据
- 查看队列中有几个元素
1.队列的实现
1.1队列的结构
因为队列是由链表来实现所以先要有一个链表,然后队列中的结构由指向链表的头和尾的指针以及一个记录链表中有多少数据的变量。
所以我们就分成两个结构体的形式:一个结构体实现单链表,一个结构体是队列的结构queue。
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _pNext;//指向下一个
QDataType _data;//数据
}QNode;
typedef struct Queue
{
QNode * _front;//指向头
QNode* _rear;//尾
int _size;//记录有几个数据
}Queue;
1.2队列的初始化
初始化一下队列,把队列中的两个指针已经记录数据个数的变量初始化
void QueueInit(Queue* q)//用指针接收结构
{
assert(q);//判空
q->_front = q->_rear = NULL;//连续赋值将两个指针都先赋值成空指针
q->_size = 0;//一开始元素个数为0
}
1.3将数据放进队列中
将数据放进队列中,其实原理类似实现链表的尾插,不同于主要是通过rear来找到尾,然后直接进行数据的插入(当rear为NULL时表示队列中是没有数据的)
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* pf = (QNode*)malloc(sizeof(QNode));//先申请一个链表节点空间
if (pf == NULL)//判断是否申请成功
{
perror("malloc");
return;
}
//判断第一个节点是否存在(队列中没有数据的时候rear是NULL)
if (q->_rear)//若不为NULL
{
q->_rear->_pNext = pf;//进行尾插,也就是在最后一个节点后面插入新生成的节点pf
q->_rear = pf;//再把尾部修改一下
}
else//当队列中没有数据的时候
{
//此时把头和尾指针都指向pf这样就创建好链表的开始了
q->_rear = pf;
q->_front = pf;
}
q->_rear->_data = data;//将rear指向后,将尾部的数据填充为所给的data
q->_rear->_pNext = NULL;//再将尾部指针的下一个位置置成NULL
q->_size++;//元素个数++
}
1.4删除数据
删除数据就相当于链表的头删,通过front找到头进行释放,然后再改变一下front头,注意队列中是否有数据
void QueuePop(Queue* q)
{
assert(q);//判空
assert(!QueueEmpty(q));//查看队列中是否有数据
QNode* tmp = q->_front->_pNext;//用tmp记录一下第二个位置的数据的地址
if (q->_front == q->_rear)//判断一下是否为最后一个元素
{
free(q->_front);//释放头指向的空间
//若是则直接吧rear和front都置为NULL
q->_front = q->_rear = NULL;
}
else//反之当不止只有一个数据时
{
free(q->_front);//同样是否头位置的空间
q->_front = tmp;//改变一下头位置然其指向第二个数据的位置也就是新头
}
q->_size--;//元素减少一位
}
1.5查看队列中是否有数据
直接查看一下size即可
bool QueueEmpty(Queue* q)
{
assert(q);//判空
return q->_size == 0;//查看size是否为0,若为则返回真(1)反之则为假(0)
}
1.6查看队列中的头尾数据
直接返回各指针指向空间的数据,注意要判断一下是否为空(否则可能会访问到NULL)
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));//判断队列是否有数据
return q->_front->_data;//返回头位置的数据
}
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));//判断队列是否有数据
return q->_rear->_data;//返回尾位置的数据
}
1.7查看队列中有几个元素
直接返回队列结构体中的size即可
int QueueSize(Queue* q)
{
return q->_size;//返回size即可
}
1.8队列的摧毁
队列的摧毁和链表的摧毁几乎一样
void QueueDestroy(Queue* q)
{
assert(q);
//从前往后的进行各链表节点释放
while (q->_front)//判断头是否为空
{
QNode* next = q->_front->_pNext;//用next记录下一个位置的地址(防止找不到)
free(q->_front);//释放当前位置
q->_front = next;//让front指向下一个位置
}
q->_front = q->_rear = NULL;//链表数据全部释放完后把front/rear也置为NULL
q->_size = 0;//把size置为0
}
2.队列的实现代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* _pNext;//指向下一个
QDataType _data;//数据
}QNode;
typedef struct Queue
{
QNode * _front;//头
QNode* _rear;//尾
int _size;
}Queue;
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_rear = NULL;
q->_size = 0;
}
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* pf = (QNode*)malloc(sizeof(QNode));//先申请一个链表节点空间
if (pf == NULL)//判断是否申请成功
{
perror("malloc");
return;
}
//判断第一个节点是否存在(队列中没有数据的时候rear是NULL)
if (q->_rear)//若不为NULL
{
q->_rear->_pNext = pf;//进行尾插,也就是在最后一个节点后面插入新生成的节点pf
q->_rear = pf;//再把尾部修改一下
}
else//当队列中没有数据的时候
{
//此时把头和尾指针都指向pf这样就创建好链表的开始了
q->_rear = pf;
q->_front = pf;
}
q->_rear->_data = data;//将rear指向后,将尾部的数据填充为所给的data
q->_rear->_pNext = NULL;//再将尾部指针的下一个位置置成NULL
q->_size++;//元素个数++
}
bool QueueEmpty(Queue* q)
{
assert(q);
return q->_size == 0;//查看size是否为0,若为则返回真(1)反之则为假(0)
}
void QueuePop(Queue* q)
{
assert(q);//判空
assert(!QueueEmpty(q));//查看队列中是否有数据
QNode* tmp = q->_front->_pNext;//用tmp记录一下第二个位置的数据的地址
if (q->_front == q->_rear)//判断一下是否为最后一个元素
{
free(q->_front);//释放头指向的空间
//若是则直接吧rear和front都置为NULL
q->_front = q->_rear = NULL;
}
else//反之当不止只有一个数据时
{
free(q->_front);//同样是否头位置的空间
q->_front = tmp;//改变一下头位置然其指向第二个数据的位置也就是新头
}
q->_size--;//元素减少一位
}
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));//判断队列是否有数据
return q->_front->_data;//返回头位置的数据
}
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));//判断队列是否有数据
return q->_rear->_data;//返回尾位置的数据
}
int QueueSize(Queue* q)
{
return q->_size;//返回size即可
}
void QueueDestroy(Queue* q)
{
assert(q);
//从前往后的进行各链表节点释放
while (q->_front)//判断头是否为空
{
QNode* next = q->_front->_pNext;//用next记录下一个位置的地址(防止找不到)
free(q->_front);//释放当前位置
q->_front = next;//让front指向下一个位置
}
q->_front = q->_rear = NULL;//链表数据全部释放完后把front/rear也置为NULL
q->_size = 0;//把size置为0
}
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量数据结构细致内容,早关注不迷路。