【C语言】队列的实现(数据结构)

前言:

相信大家在生活中经常排队买东西,今天学习的队列就跟排队买东西一样,先来买的人就买完先走,也就是先进先出。废话不多说,进入咱们今天的学习吧。

目录

前言:

队列的概念

队列的实现

队列的定义

入队列

判空

出队列

队列初始化

获取队头数据

获取队尾数据

获取有效数量

队列销毁

队列详细代码

头文件Queue.h

函数文件Queue.c

测试Text.cjt


队列的概念

想要去实现队列,首先要了解队列的结构和内容。

队列有队头个队尾,出队列只能在队头出(头删), 入队列只能在队尾入(尾插)。
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先
进先出FIFO(First In First Out)。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一 端称为队头。

队列的实现

前面我们学习了单链表的基本实现,如果掌握了单链表,那么队列的实现就轻而易举了。

因为队列的本质是先进先出,也就是和头节点删除一样,如果我们利用顺序表的结构来实现队列,删掉一个头节点,后面的数据都要往前移动一位,时间复杂度为O(N),所以我们利用单链表来实现队列,既方便又简洁。

队列的定义

我们既然利用单链表来实现队列,那么一个节点里面就会包含一个指向下一个节点的指针和我们要存放的数据。

cs 复制代码
typedef int QDataType;
//表示队列节点的定义
typedef struct QListNode
{
	struct QListNode* next;
	QDataType val;
}QNode;

这里将int 定义为 QDataType 方便数据类型的更改。

在实现单链表的时候我们只需要了一个头指针,实现队列的时候我们需要加上一个尾指针,这样方便我们找到头尾数据,同时还可以避免遍历找尾,提高的算法的效率。

更重要的是,在的单链表实现中我们的头删,头插都用到了二级指针,考虑到链表为空,只有二级指针才能更好的方便改变指向节点指针的值,但队列我们增加的一个尾指针的话,改变头节点里面的内容就不需要传二级指针了。

cpp 复制代码
//队列的结构
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

后面我们要计算队列中有效数据的元素个数,所以我们加一个size进去。

入队列

数据插入队列的时候,我们要考虑队列为空的情况,最后要注意size要++!!!

cs 复制代码
//队尾入队列
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//考虑newnode为空的情况
	{
		printf("malloc fail!!!");
		exit(1);
	}
	newnode->next = NULL;
	newnode->val = x;

	if (QueueEmpty(q))//队列为空
	{
		q->head = q->tail = newnode;
	}
	else {           //队列不为空
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;//插入数据之后不要忘了把size++
}

判空

如果为空则返回非零结果,如果非空则返回0

cs 复制代码
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}

出队列

这里也要注意,如果只有一个节点的时候,q->head = NULL的同时要保证q->tail也要为空,不然就会出现野指针的情况!

cs 复制代码
//队头出队列
void QueuePop(Queue* q)
{
	assert(q);
    assert(q->head);
	if (q->head->next == NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else {
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->size--;
}

一定要写assert(q->head);这样就保证下面的q->head->next没有问题,这样写是为了防止空指针被解引用!

队列初始化

cs 复制代码
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}

获取队头数据

cs 复制代码
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->val;
}

获取队尾数据

cs 复制代码
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->val;
}

这是也要注意要对q->head和q->tail进行断言。

获取有效数量

cs 复制代码
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

队列销毁

cs 复制代码
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* pcur = q->head;
	while (pcur)
	{
		QNode* next = pcur->next;
		free(q->head);
		pcur = next;
		
	}
	q->head = q->tail = NULL;
	q->size = 0;
}

在while循环里面要注意将pcur的下一个节点用新指针保存起来,这样更方便我们去释放空间。

队列详细代码

头文件Queue.h

cs 复制代码
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef int QDataType;
//表示队列节点的定义
typedef struct QListNode
{
	struct QListNode* next;
	QDataType val;
}QNode;
//队列的结构
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

//初始化队列
void QueueInit(Queue* q);
//队尾入队列
void QueuePush(Queue* q,QDataType x);
//队头出队列
void QueuePop(Queue* q);
//获取队列头部元素
QDataType QueueFront(Queue* q);
//获取队列尾部元素
QDataType QueueBack(Queue* q);
//获取队列中有效元素个数
int QueueSize(Queue* q);
//检验队列是否为空,如果为空则返回非零结果,如果非空则返回0
int QueueEmpty(Queue* q);
//销毁队列
void QueueDestroy(Queue* q);

函数文件Queue.c

cs 复制代码
#include"Queue.h"
//初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}
//队尾入队列
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//考虑newnode为空的情况
	{
		printf("malloc fail!!!");
		exit(1);
	}
	newnode->next = NULL;
	newnode->val = x;

	if (QueueEmpty(q))//队列为空
	{
		q->head = q->tail = newnode;
	}
	else {           //队列不为空
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;//插入数据之后不要忘了把size++
}

//队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	if (q->head->next == NULL)
	{
		free(q->head);
		q->head = q->tail = NULL;
	}
	else {
		QNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->size--;
}
//获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->val;
}
//获取队列尾部元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->val;
}
//获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
//检验队列是否为空,如果为空则返回非零结果,如果非空则返回0
int QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}
//销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* pcur = q->head;
	while (pcur)
	{
		QNode* next = pcur->next;
		free(q->head);
		pcur = next;
		
	}
	q->head = q->tail = NULL;
	q->size = 0;
}

测试Text.cjt

cs 复制代码
#include"Stack.h"
#include"Queue.h"
void QueueText()
{
	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");
	}
	QueueDestroy(&q);
}
int main()
{
	QueueText();
	return 0;
}

今天的分享就到这啦!如果大家有所感悟或者见解多多分享哈。

记得三连哦,有不好的地方欢迎大佬指正!

相关推荐
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++
小辛学西嘎嘎1 小时前
C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
c语言·开发语言·c++
韭菜盖饭1 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode
无敌最俊朗@1 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
♡喜欢做梦2 小时前
【数据结构】ArrayList与LinkedList详解!!!——Java
java·开发语言·数据结构·链表
好心的小明2 小时前
【深圳大学】数据结构A+攻略(计软版)
数据结构
熬夜学编程的小王2 小时前
【初阶数据结构篇】插入、希尔、选择、堆排序
数据结构·c++·插入排序·选择排序·希尔排序
三小尛2 小时前
快速排序(C语言)
数据结构·算法·排序算法
椅子哥2 小时前
数据结构--排序算法
java·数据结构·算法·排序算法
DDDiccc2 小时前
JAVA学习日记(十五) 数据结构
数据结构·学习