目录
一、队列的概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。采用链表实现队列比较方便,出队就类似于头删,入队就为尾插。
二、队列的实现
1. 创建队列
需要定义两个结构体,一个用来定义节点,一个用来定义队列,即队头队尾等信息。
//创建队列结构 typedef int QDataType; //一个节点 typedef struct QueueNode { QDataType data; //存储数据 struct QueueNode* next; //记录下一个节点 }QNode; //保存队头和队尾 typedef struct Queue { QNode* head; //头指针 QNode* tail; //尾指针 }Queue;
2. 队列初始化
队列可以为空,但是指向头指针和尾指针的结构体不能为空,所以一开始就要断言。其次,在插入数据前,队列肯定是空的,所以直接把头指针和尾指针置空即可。
//初始化队列 void QueueInit(Queue* pq) { assert(pq);//传入的队列地址不能为空 pq->head = pq->tail = NULL; }
3. 销毁队列
销毁队列就是把队列的每个数据都销毁掉,那么需要遍历链表进行挨个销毁free。首先定义一个cur指针指向pq->head,用来保存第一个数据,遍历cur,如果不为空,就free。最后把tail和head置空即可。
//销毁队列 void QueueDestory(Queue* pq) { assert(pq); QNode* cur = pq->head; while (cur) { QNode* next = cur->next; free(cur); cur = next; } pq->head = pq->tail = NULL; }
4. 入队
入队就类似于链表尾插,首先创建一个新节点newnode,初始化节点。下来分为队列为空和有数据。若对垒为空,则将head和tail节点指向新节点newnode即可。有数据则需要将tail的next指向新节点newnode,然后令newnode为tail新的尾部即可。
//入队 void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建一个新节点 assert(newnode); newnode->next = NULL; newnode->data = x; if (pq->tail == NULL)//空队列则两其头尾均指向新节点 { assert(pq->head == NULL); pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } }
5. 出队
出队就类似于链表的头删,分两种情况,一种是当队列仅剩一个数据时,此时head=tail,若删除head,则tail变为野指针了,此中情况需要单独讨论,分别置空head和tail即可。
一般情况,为定义一个next指针保存头节点的下一个节点,再删除head,令next为新的head。
//出队 void QueuePop(Queue* pq) { assert(pq); assert(pq->head && pq->tail);//头尾均不能为空 if (pq->head->next == NULL)//当只有一个节点时 { free(pq->head); pq->head = pq->tail = NULL; } else { QNode* next = pq->head->next; free(pq->head); pq->head = next; } }
6. 判空
判断队列为空,则head和tail均为空时候。
//判空 bool QueueEmpty(Queue* pq) { assert(pq); return pq->head == NULL; }
7. 获取队列元素个数
遍历队列,定义指针从头开始遍历,个数++,指向空时停止。
再队列结构中定义一个size专门用来保存节点个数。
下面为遍历获取队列元素个数:
//获取有效元素个数 size_t QueueSize(Queue* pq) { assert(pq); QNode* cur = pq->head; size_t size = 0; while (cur) { size++; cur = cur->next; } return size; }
8. 获取队列头部
当队列不为空时候,直接返回队列头部元素即可。
//获取队头元素 QDataType QueueFront(Queue* pq) { assert(pq); assert(pq->head); //头部不能为空 return pq->head->data; }
9. 获取队列尾部元素
//获取队尾元素 QDataType QueueBack(Queue* pq) { assert(pq); assert(pq->tail); //尾部不能为空 return pq->tail->data; }
三、总代码
Queue.h
#pragma once
#include<stdio.h>
#include<Stdlib.h>
#include<assert.h>
#include<stdbool.h>
//创建队列结构
typedef int QDataType;
//一个节点
typedef struct QueueNode
{
QDataType data; //存储数据
struct QueueNode* next; //记录下一个节点
}QNode;
//保存队头和队尾
typedef struct Queue
{
QNode* head; //头指针
QNode* tail; //尾指针
}Queue;
//初始化队列
void QueueInit(Queue* pq);
//销毁队列
void QueueDestory(Queue* pq);
//入队
void QueuePush(Queue* pq, QDataType x);
//出队
void QueuePop(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//获取有效元素个数
size_t QueueSize(Queue* pq);
//获取队头元素
QDataType QueueFront(Queue* pq);
//获取队尾元素
QDataType QueueBack(Queue* pq);
Queue.c
#include"Queue.h"
//初始化队列
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
//销毁队列
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;//指针置空
}
//入队
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建一个新节点
assert(newnode);
newnode->next = NULL;
newnode->data = x;
if (pq->tail == NULL)//空队列则两其头尾均指向新节点
{
assert(pq->head == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
//出队
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head && pq->tail);//头尾均不能为空
if (pq->head->next == NULL)//当只有一个节点时
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
//判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
//获取有效元素个数
size_t QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
size_t size = 0;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
//获取队头元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);//头不能为空才可以获取头部数据
return pq->head->data;
}
//获取队尾元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
Test.c
#include"Queue.h"
void TestQueue()
{
Queue q;
QueueInit(&q);
//插入数据
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
//打印
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\n");
}
int main()
{
TestQueue();
return 0;
}