1. 队列的定义
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
2. 队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
typedef int QDataType;
typedef struct QueueNode
{
struct QNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
//队列初始化
void QueueInit(Queue* pq);
//队列销毁
void QueueDestory(Queue* pq);
//入队列
void QueuePush(Queue* pq, QDataType x);
//出队列
void QueuePop(Queue* pq);
//返回队列首元素
QDataType QueueFront(Queue* pq);
//返回队尾元素
QDataType QueueBack(Queue* pq);
//返回队列长度
int QueueSize(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
以上是本次要学习的一些队列的操作, 需要注意的是, QueueNode指的是队列中每个结点, 都有一个data存放数据, 一个next指向下一个结点, 而Queue代表的就是这个队列了, 有两个指针, 分别指向队列的头和尾, 还有一个size记录队列的大小
2.1 队列初始化
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
很简单, 就是将队列进行初始化
2.2 入队列
//入队列
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
//创建一个新结点
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail\n");
return;
}
newnode->data = x;
newnode->next = NULL;
//第一次插入需要特殊处理
if (pq->size == 0)
{
pq->phead = newnode;
pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
入队列实际就是将新节点插入尾指针的后面, 因为此次使用的是不带头的单链表, 所以第一次入队列需要特殊处理, 即对头指针进行修改
2.3 出队列
//出队列
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
//一个结点
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* del = pq->phead;
pq->phead = pq->phead->next;
free(del);
}
pq->size--;
}
和插入一样, 需要对只有一个结点的情况特殊处理, 将phead和ptail置空, 防止出现野指针的情况, 还需要判断队列是否为空, 如果为空则删除失败
2.4 返回队首元素
//返回队列首元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->phead->data;
}
很简单, 只要队列不为空, 直接返回phead指向的结点的data就可以了
2.5 返回队尾元素
//返回队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->ptail->data;
}
和上面一个道理
2.6 返回队列长度
//返回队列长度
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
前面记录下队列的长度在这里就用到了
2.7 判断队列是否为空
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->phead == NULL
&& pq->ptail == NULL;
}
也很简单那, 当phead和ptail同时为空的时候, 队列就是空, 此时返回true, 如果不同时为空, 则返回false, 也可以使用size来判断队列是否为空
2.8 队列的销毁
//队列销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur != NULL)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
队列中每个结点都是单独malloc出来的, 所以不能一次性全部释放掉, 应该设置一个cur指向这个队列, 从队头开始向队尾, 一个结点一个结点的释放
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
//队列初始化
void QueueInit(Queue* pq);
//队列销毁
void QueueDestory(Queue* pq);
//入队列
void QueuePush(Queue* pq, QDataType x);
//出队列
void QueuePop(Queue* pq);
//返回队列首元素
QDataType QueueFront(Queue* pq);
//返回队尾元素
QDataType QueueBack(Queue* pq);
//返回队列长度
int QueueSize(Queue* pq);
//判断队列是否为空
bool QueueEmpty(Queue* pq);
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
//队列销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur != NULL)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
//入队列
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
//创建一个新结点
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail\n");
return;
}
newnode->data = x;
newnode->next = NULL;
//第一次插入需要特殊处理
if (pq->size == 0)
{
pq->phead = newnode;
pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
//一个结点
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* del = pq->phead;
pq->phead = pq->phead->next;
free(del);
}
pq->size--;
}
//返回队列首元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->phead->data;
}
//返回队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(&pq));
return pq->ptail->data;
}
//返回队列长度
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->phead == NULL
&& pq->ptail == NULL;
}