文章目录
前言
本文总结学习队列(单链表式)的各个接口实现。
一、队列(单链表式)头文件Queue.h
本节主要包含:结构体类型创建,函数声明,头文件包含
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
// 当队列的数值不为int类型时,方便修改
typedef int QDataType;
// 单链表结构(表示队列,定义结点)
typedef struct QListNode
{
struct QListNode* next;
QDataType val;
}QNode;
// 队列的结构(定义头尾指针,方便出入队列)
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
// 初始化队列
void QueueInit(Queue* pq);
// 销毁队列
void QueueDestroy(Queue* pq);
// 队尾入队列
void QueuePush(Queue* pq, QDataType val);
// 队头出队列
void QueuePop(Queue* pq);
// 检测队列是否为空
bool QueueEmpty(Queue* pq);
// 获取队列中有效元素个数
size_t QueueSize(Queue* pq);
// 获取队列头部元素
QDataType QueueFront(Queue* pq);
// 获取队列尾部元素
QDataType QueueBack(Queue* pq);
二、队列(单链表式)各接口具体实现Queue.c
本节主要包含:各个接口的实现方法
2.1 初始化队列
// 初始化队列
void QueueInit(Queue* pq) // point queue简写
{
assert(pq);
pq->head = NULL;
pq->tail = NULL;
}
2.2 销毁队列
// 销毁队列
void QueueDestroy(Queue* pq)
{
assert(pq);
// 遍历链表,将每个结点释放掉,最后将头尾指针也置空
QNode* cur = pq->head;
while (NULL != cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = NULL;
pq->tail = NULL;
// free(pq); 为啥不用??????????????因为初始状态是结构体,而不是结构体指针
}
2.3 队尾入队列
// 队尾入队列
void QueuePush(Queue* pq, QDataType val)
{
assert(pq);
// 创建一个新结点,因为所有接口函数只有此函数需要,所以无需单独创建函数
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (NULL == newnode) // 或者assert也可以
{
printf("malloc fail\n");
exit(-1);
}
else
{
// 初始化新结点!!!!!!!!别忘记
newnode->next = NULL;
newnode->val = val;
if (NULL == pq->tail)
{
//assert(pq->head == NULL); //没必要,原因见下:
// 当该链表的尾结点指针为NULL,此时头结点也一定为NULL时,将该结点作为头尾结点
pq->head = newnode;
pq->tail = newnode;
}
else
{
// 连接新尾结点
pq->tail->next = newnode;
// 更新尾结点指针
pq->tail = newnode;
}
}
}
2.4 队头出队列
// 队头出队列
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head && pq->tail);
// 易错!!!!!!不加下面语句的代码会出现:
// 当最后一个结点出队列后,head为NULL,而tail仍为尾结点,且改该尾结点已经被free了,此时tail为野指针
// 补充代码:
if (NULL == pq->head->next)
{
free(pq->head);
pq->head = NULL;
pq->tail = NULL;
}
else
{
// 记录头结点下一个位置
QNode* next = pq->head->next;
free(pq->head);
// 更新头结点指针
pq->head = next;
}
}
2.5 检测队列是否为空
// 检测队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
// 注:当仅剩一个结点时,二者相等,但是不为空,所以二者相等不能用来判定空
return NULL == pq->tail;// 当尾结点指针为空时,头结点指针也必定为空;当头结点指针为空时,尾结点指针也必定为空
}
2.6 获取队列中有效元素个数
// 获取队列中有效元素个数
size_t QueueSize(Queue* pq)
{
assert(pq);
// 不能使用指针相减来求,因为链表的物理结构不连续!!!!!!
// 方法1,在初始的队列结构中新增一个size变量,每次更新size来获取元素个数
// 方法2,数数
size_t num = 0;
QNode* cur = pq->head;
while (NULL != cur) // 或while(cur)
{
num++;
cur = cur->next;
}
return num;
}
2.7 获取队列头部元素
// 获取队列头部元素
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->val;
}
2.8 获取队列尾部元素
// 获取队列尾部元素
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->val;
}
三、队列(单链表式)接口测试test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "Queue.h"
int main()
{
// 初始状态的队列:一个队列结构体来控制
Queue q = { 0 };
// 初始化队列
QueueInit(&q);
// 队尾入队列
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
// 队列打印
while (!QueueEmpty(&q))// 检测队列是否为空
{
printf("%d\n", QueueFront(&q));// 获取队列头部元素
// 队头出队列
QueuePop(&q);
}
// 销毁队列
QueueDestroy(&q);
return 0;
}
总结
这里对文章进行总结:
以上就是今天总结的内容,本文包括了C语言实现队列(单链表式)接口各个接口,分享给大家。
真💙欢迎各位给予我更好的建议,欢迎访问!!!小编创作不易,觉得有用可以一键三连哦,感谢大家。peace
希望大家一起坚持学习,共同进步。梦想一旦被付诸行动,就会变得神圣。
欢迎各位大佬批评建议,分享更好的方法!!!🙊🙊🙊