文章目录
1. 队列基本概念
1.1 队列概念
队列:只允许一端进行插入数据操作,在另一侧进行删除数据操作的特殊线性表。队列是先进先出LIFO(First in First out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
- 入队出队的形式:一种入队顺序,只有一种出队顺序
1.2 队列的存储结构
- 队列顺序存储
入队:不需要挪动数据,时间复杂度为O(1)
出队:需要挪动数据,所有的元素都要往前移,时间复杂度为O(n)
所以顺序表存储队列还是相对麻烦的
- 队列链式存储
首先我们需要定义两个指针,分别为队头指针 phead 指向第一个节点,队尾节点 ptail 指向尾结点
入队(尾插):时间复杂度为O(1)
出队(头删):时间复杂度为O(1)
所以用链表存储队列还是比较方便简单快捷的
2. 队列的实现
首先,我们还是先创建一个工程:
- Queue.h—队列的类型定义、接口函数的声明、所包含的头文件
- Queue.c—接口函数的具体实现
- test.c—主函数、测试
2.1 队列的定义
typedef int QDataType;
//队列节点结构
typedef struct QueueNode
{
struct QueueNode* next;//节点指针
QDataType data;//节点数据
}QNode;
//队列的链式结构
typedef struct Queue
{
QNode* phead;//队头指针
QNode* ptail;//队尾指针
}Queue;
2.2 队列初始化
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);//断言
pq->phead = pq->ptail = NULL;//初始化为空队列
}
2.3 队列的销毁
//队列的销毁
void QueueDestory(Queue* pq)
{
assert(pq);//断言
QNode* cur = pq->phead;//记录队头节点
while (cur)//遍历队列
{
QNode* next = cur->next;
free(cur);//释放当前头结点
cur = next;
}
cur = NULL;//置空
pq->phead = pq->ptail = NULL;//队列为空
}
2.4 入队(尾插)
//入队
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);//断言
QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态申请节点
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;//尾结点的next置空
if (pq->phead == NULL)//队列为空队列
{
pq->phead = pq->ptail = newnode;
}
else//队列不为空
{
pq->ptail->next = newnode;//尾插
pq->ptail = newnode;//更新队尾指针
}
}
2.5 出队(头删)
//出队
void QueuePop(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
//1.一个
//2.多个
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;//更新队头指针
}
}
2.6 获取队头元素
//获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
return pq->phead->data;
}
2.7 获取队尾元素
//获取队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
return pq->ptail->data;
}
2.8 获取队列元素个数
//获取队列元素个数
int QueueSize(Queue* pq)
{
assert(pq);//断言
int size = 0;//初始化元素个数
QNode* cur = pq->phead;
while (cur)//遍历队列
{
++size;
cur = cur->next;
}
return size;
}
2.9 判断队列是否为空
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);//断言
return pq->phead == NULL;
}
2.10 测试队列入队出队操作
void test01()
{
Queue q;
QueueInit(&q);
//入队
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
//出队
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));//获取队头元素
QueuePop(&q);//出队
}
printf("\n");
QueueDestory(&q);//释放队列
}
3. 完整代码展示
- Queue.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int QDataType;
//队列节点结构
typedef struct QueueNode
{
struct QueueNode* next;//节点指针
QDataType data;//节点数据
}QNode;
//队列的链式结构
typedef struct Queue
{
QNode* phead;//队头指针
QNode* ptail;//队尾指针
}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);//判断队列是否为空
- Queue.c
#include "Queue.h"
//队列初始化
void QueueInit(Queue* pq)
{
assert(pq);//断言
pq->phead = pq->ptail = NULL;//初始化为空队列
}
//队列的销毁
void QueueDestory(Queue* pq)
{
assert(pq);//断言
QNode* cur = pq->phead;//记录队头节点
while (cur)//遍历队列
{
QNode* next = cur->next;
free(cur);//释放当前头结点
cur = next;
}
cur = NULL;//置空
pq->phead = pq->ptail = NULL;//队列为空
}
//入队
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);//断言
QNode* newnode = (QNode*)malloc(sizeof(QNode));//动态申请节点
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;//尾结点的next置空
if (pq->phead == NULL)//队列为空队列
{
pq->phead = pq->ptail = newnode;
}
else//队列不为空
{
pq->ptail->next = newnode;//尾插
pq->ptail = newnode;//更新队尾指针
}
}
//出队
void QueuePop(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
//1.一个
//2.多个
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;//更新队头指针
}
}
//获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
return pq->phead->data;
}
//获取队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);//断言
assert(pq->phead);//不能为空队列
return pq->ptail->data;
}
//获取队列元素个数
int QueueSize(Queue* pq)
{
assert(pq);//断言
int size = 0;//初始化元素个数
QNode* cur = pq->phead;
while (cur)//遍历队列
{
++size;
cur = cur->next;
}
return size;
}
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);//断言
return pq->phead == NULL;
}
- test.c
#include "Queue.h"
void test01()
{
Queue q;
QueueInit(&q);
//入队
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
//出队
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));//获取队头元素
QueuePop(&q);//出队
}
printf("\n");
QueueDestory(&q);//释放队列
}
int main()
{
test01();
system("pause");
return 0;
}