当前位置: 首页 > article >正文

数据结构 ——— C语言实现链式队列

目录

队列的概念以及示意图

数组队列和链式队列

链式队列的结构 

实现链式队列的准备工作

实现链式队列

1. 初始化

2. 打印队列的所有数据

3. 数据入队列(尾插)

4. 数据出队列(头删)

5. 访问队头的数据

6. 访问队尾的数据

7. 队列数据总个数

8. 判断队列是否为空

9. 释放队列的所有节点

10. 以队列逻辑遍历所有数据

Queue.h 的所有代码 

Queue.c 的所有代码


队列的概念以及示意图

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表
队列具有先进先出的逻辑

入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

队列结构示意图:


数组队列和链式队列

数组队列:

把首元素当作队头,尾元素当作队尾
那么出队列就需要删除首元素,在把后面的元素向前挪动,降低了效率
且当空间不够时需要扩容,就存在异地扩容的问题,也会降低效率

链式队列:

把头节点当作队头,尾节点当作队尾
那么出队列只需要将指向头节点的指针指向下一个节点,在释放头节点即可,效率为O(1)
入队列只需要在尾节点尾插即可,所以选择实现链式队列


链式队列的结构 

// 数据类型
typedef int QDataType;

// 链式队列每个节点的结构
typedef struct QueueNode
{
	struct QueueNode* next; //指向下一个节点的指针
	
	QDataType data; //当前节点的数据
}QNode;

// 链式队列的结构
typedef struct Queue
{
	QNode* phead; //指向队头节点的指针

	QNode* ptail; //指向队尾节点的指针

	int size; //队列的总数据个数
}Queue;

实现链式队列的准备工作

创建3个文件

test.c 文件:用来测试增删查改功能是否完善

Queue.h 文件:用来声明动态顺序表的结构以及声明增删查改函数 

Queue.c 文件:用来实现动态顺序表的增删查改及功能函数


实现链式队列

1. 初始化

void QueueInit(Queue* pq)
{
	assert(pq);

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

2. 打印队列的所有数据

void QueuePrint(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;

	printf("head<-");
	while (cur != NULL)
	{
		printf("%d<-", cur->data);

		cur = cur->next;
	}
	printf("tail\n\n");
}

3. 数据入队列(尾插)

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	// 开辟节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));

	// 判断是否开辟成功
	if (newnode == NULL)
	{
		assert(pq->ptail == NULL);
		return;
	}

	newnode->data = x;
	newnode->next = NULL;

	if (pq->phead == NULL)
	{
		// 双重判断,更保险
		assert(pq->ptail);

		pq->phead = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}

	pq->size++;
}

分两种情况判断:

当队列没有节点时:直接将指向头尾节点的指针指向新节点
当队列有节点时:pq->ptail 就是指向最后一个节点的指针,那么 pq->ptail->next 就是节点的 next,直接指向新节点,再将 pq->ptail指向新节点
数据成功入队列,最后 size 自增1

测试代码:


4. 数据出队列(头删)

void QueuePop(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->phead == NULL)
	{
		printf("无数据可出队列\n");
		return;
	}

	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}

	pq->size--;
}

分三种情况判断:

队列没有节点时:直接报错并返回
队列只有一个节点时:释放头节点,并将指向头尾节点的指针都置空
队列有多个节点时:保存下一个节点,再释放头节点,最后将指向头节点的指针指向保存的下一个节点
数据成功出队列,最后 size 自减1

测试代码:


5. 访问队头的数据

QDataType QueueFront(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->phead == NULL)
	{
		printf("无数据可访问\n");
		return;
	}

	return pq->phead->data;
}

6. 访问队尾的数据

QDataType QueueBack(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->ptail == NULL)
	{
		printf("无数据可访问\n");
		return;
	}

	return pq->ptail->data;
}

7. 队列数据总个数

int	QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

8. 判断队列是否为空

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return (pq->phead == NULL) && (pq->ptail == NULL);
}

9. 释放队列的所有节点

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;

	while (cur != NULL)
	{
		QNode* next = cur->next;

		free(cur);

		cur = next;
	}

	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

10. 以队列逻辑遍历所有数据

Queue q;
QueueInit(&q);

for (int i = 1; i <= 5; i++)
{
	QueuePush(&q, i);
}

printf("head<-");
while (!QueueEmpty(&q))
{
	// 访问当前队头数据
	printf("%d<-", QueueFront(&q));

	// 移除当前队头数据
	QueuePop(&q);
}
printf("tail\n\n");

测试代码:


Queue.h 的所有代码 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>


// 数据类型
typedef int QDataType;

// 链式队列每个节点的结构
typedef struct QueueNode
{
	struct QueueNode* next; //指向下一个节点的指针
	
	QDataType data; //当前节点的数据
}QNode;

// 链式队列的结构
typedef struct Queue
{
	QNode* phead; //指向队头节点的指针

	QNode* ptail; //指向队尾节点的指针

	int size; //队列的总数据个数
}Queue;


// 初始化
void QueueInit(Queue* pq);

// 打印
void QueuePrint(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 = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

// 打印
void QueuePrint(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;

	printf("head<-");
	while (cur != NULL)
	{
		printf("%d<-", cur->data);

		cur = cur->next;
	}
	printf("tail\n\n");
}

// 数据入队列(尾插)
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	// 开辟节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));

	// 判断是否开辟成功
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

	newnode->data = x;
	newnode->next = NULL;

	if (pq->phead == NULL)
	{
		// 双重判断,更保险
		assert(pq->ptail == NULL);

		pq->phead = newnode;
		pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}

	pq->size++;
}

// 数据出队列(头删)
void QueuePop(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->phead == NULL)
	{
		printf("无数据可出队列\n");
		return;
	}

	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = NULL;
		pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}

	pq->size--;
}

// 访问队头的数据
QDataType QueueFront(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->phead == NULL)
	{
		printf("无数据可访问\n");
		return -1;
	}

	return pq->phead->data;
}

// 访问队尾的数据
QDataType QueueBack(Queue* pq)
{
	assert(pq);

	// 队列没有数据时
	if (pq->ptail == NULL)
	{
		printf("无数据可访问\n");
		return -1;
	}

	return pq->ptail->data;
}

// 队列数据总个数
int	QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

// 是否为空
bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return (pq->phead == NULL) && (pq->ptail == NULL);
}

http://www.kler.cn/news/366161.html

相关文章:

  • 配置nginx服务通过ip访问多网站
  • 第二代 GPT-SoVITS V2:解锁语音克隆与合成的无限可能
  • 【移动应用开发】界面设计(二)实现水果列表页面
  • Python与MySQL
  • springboot3.x使用@NacosValue无法获取配置信息问题解决
  • 算法革新决定未来!深挖数字北极星3.0背后的技术逻辑
  • 干丹岩教授
  • 公司怎么能帮员工统一管理朋友圈
  • Java 泛型 Lambda 表达式
  • 【TFR-Net】基于transformer的鲁棒多模态情感分析特征重构网络
  • 【算法】归并排序概念及例题运用
  • 包过滤防火墙在哪一层工作
  • 【动手学强化学习】part2-动态规划算法
  • 电商平台数据分析:从商品数据收集到挖掘的完整流程
  • arco-design 自定义table和for循环自定义form-item并添加自定义校验
  • 912.排序数组(桶排序)
  • 文件下载漏洞
  • 中小企业设备管理流程优化:Spring Boot系统实现
  • react项目因eslint检测未通过而Failed to compile编译失败
  • 线性可分支持向量机的原理推导 9-18基于拉格朗日函数L(w,b,α) 对w求偏导 公式解析
  • 【设计模式-我的思考】套餐模式
  • 【有啥问啥】CLIP Adapter:提升视觉语言模型性能的利器
  • LeetCode 每周算法 10(多维动态规划、技巧)
  • 银行客户贷款行为数据挖掘与分析
  • 入侵检测算法平台部署LiteAIServer视频智能分析平台行人入侵检测算法
  • 分布式光伏发电系统电气一次部分设计(开题报告3)