一、定义
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的特性。
队尾:进行插入操作的一端。
队头:进行删除操作的一端。
二、结构体定义
// 链式结构:表示队列
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* front;//队头
QNode* rear;//队尾
}Queue;
若采用顺序表的方式实现队列,随着出队入队的操作,队头指针和队尾指针的移动,队头前的空间就可能发生内存泄漏,或出现假溢出问题。对此有两种解决方法,一种是采用链表的方式实现队列,一种是采用循环队列,这里采用的是链表的方式实现队列,随后会发布循环队列的实现方法。
三、接口实现
void Queue_Tese();//队列功能测试函数
QNode* buyQNode(QDataType data);//带头结点的单链表
void QueueInit(Queue* q);// 初始化队列
void QueuePush(Queue* q, QDataType data);// 队尾入队列
void QueuePop(Queue* q);// 队头出队列
QDataType QueueFront(Queue* q);// 获取队列头部元素
QDataType QueueBack(Queue* q);// 获取队列队尾元素
int QueueSize(Queue* q);// 获取队列中有效元素个数
int QueueEmpty(Queue* q);// 检测队列是否为空,为空返回1,非空返回0
void QueueDestroy(Queue* q);// 销毁队列
1.创建带头结点的单链表
QNode* buyQNode(QDataType data) {//带头结点的单链表
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL) {
assert(0);
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
使用带头结点的单链表实现队列,可以简化实现过程的很多操作。
2.初始化队列
void QueueInit(Queue* q) {// 初始化队列
assert(q);
q->front = buyQNode(0);
q->rear = q->front;
}
将队列头尾指针都指向头结点即可。
3.入队
void QueuePush(Queue* q, QDataType data) {// 队尾入队列
assert(q);
QNode* newNode = buyQNode(data);
q->rear->next = newNode;
q->rear = newNode;
}
只能在队尾入队。
4.判空
int QueueEmpty(Queue* q) {// 检测队列是否为空,为空返回1,非空返回0
assert(q);
return q->front == q->rear;
}
队头队尾指针都在初始位置指向头结点,即队列为空,若用顺序表实现则是队头队尾都在0号位置即队列为空。
5.出队
void QueuePop(Queue* q){// 队头出队列
assert(q);
if (QueueEmpty(q)) {//判空
return;
}
QNode* delNode = q->front->next;
q->front->next = delNode->next;
if (delNode == q->rear) {//若队列只有一个元素,出队列后要将队尾放到头结点处
q->rear = q->front;
}
free(delNode);
}
出队列只能在队头出队。因为这里采用的是带头结点的单链表实现队列,所以在队列只有一个元素时出队列,需要把队尾指针放回到头节处。
6.获取队头
QDataType QueueFront(Queue* q) {// 获取队列头部元素
assert(q);
return q->front->next->data;
}
7.获取队尾
QDataType QueueBack(Queue* q) {// 获取队列队尾元素
assert(q);
return q->rear->data;
}
8.获取队列中有效元素个数
int QueueSize(Queue* q) {// 获取队列中有效元素个数
assert(q);
QNode* cur = q->front->next;
int len = 0;
while (cur) {
len++;
cur = cur->next;
}
return len;
}
通过单链表的遍历计数实现。
9.队列销毁
void QueueDestroy(Queue* q) {// 销毁队列
assert(q);
QNode* cur = q->front->next;
while (cur) {
q->front->next = cur->next;
free(cur);
cur = q->front->next;
}
free(q->front);
q->front = q->rear = NULL;
}
循环释放每个结点,最后置空头尾指针。
四、接口测试
1.测试用例
void Queue_Tese() {//队列功能测试函数
Queue q;
QueueInit(&q);
printf("size = %d\n", QueueSize(&q));
// 入队列
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
// 出队列
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
QueueDestroy(&q);
}
2.测试结果
五、完整代码
#include<stdio.h>
#include<assert.h>
#include<malloc.h>
// 链式结构:表示队列
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* front;//队头
QNode* rear;//队尾
}Queue;
void Queue_Tese();//队列功能测试函数
QNode* buyQNode(QDataType data);//带头结点的单链表
void QueueInit(Queue* q);// 初始化队列
void QueuePush(Queue* q, QDataType data);// 队尾入队列
void QueuePop(Queue* q);// 队头出队列
QDataType QueueFront(Queue* q);// 获取队列头部元素
QDataType QueueBack(Queue* q);// 获取队列队尾元素
int QueueSize(Queue* q);// 获取队列中有效元素个数
int QueueEmpty(Queue* q);// 检测队列是否为空,为空返回1,非空返回0
void QueueDestroy(Queue* q);// 销毁队列
int main() {
Queue_Tese();
return 0;
}
QNode* buyQNode(QDataType data) {//带头结点的单链表
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL) {
assert(0);
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void QueueInit(Queue* q) {// 初始化队列
assert(q);
q->front = buyQNode(0);
q->rear = q->front;
}
void QueuePush(Queue* q, QDataType data) {// 队尾入队列
assert(q);
QNode* newNode = buyQNode(data);
q->rear->next = newNode;
q->rear = newNode;
}
int QueueEmpty(Queue* q) {// 检测队列是否为空,为空返回1,非空返回0
assert(q);
return q->front == q->rear;
}
void QueuePop(Queue* q){// 队头出队列
assert(q);
if (QueueEmpty(q)) {//判空
return;
}
QNode* delNode = q->front->next;
q->front->next = delNode->next;
if (delNode == q->rear) {//若队列只有一个元素,出队列后要将队尾放到头结点处
q->rear = q->front;
}
free(delNode);
}
QDataType QueueFront(Queue* q) {// 获取队列头部元素
assert(q);
return q->front->next->data;
}
QDataType QueueBack(Queue* q) {// 获取队列队尾元素
assert(q);
return q->rear->data;
}
int QueueSize(Queue* q) {// 获取队列中有效元素个数
assert(q);
QNode* cur = q->front->next;
int len = 0;
while (cur) {
len++;
cur = cur->next;
}
return len;
}
void QueueDestroy(Queue* q) {// 销毁队列
assert(q);
QNode* cur = q->front->next;
while (cur) {
q->front->next = cur->next;
free(cur);
cur = q->front->next;
}
free(q->front);
q->front = q->rear = NULL;
}
void Queue_Tese() {//队列功能测试函数
Queue q;
QueueInit(&q);
printf("size = %d\n", QueueSize(&q));
// 入队列
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
QueuePush(&q, 6);
QueuePush(&q, 7);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
// 出队列
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
printf("\nsize = %d\n", QueueSize(&q));
QueueDestroy(&q);
}