C语言实现队列--数据结构

news2024/10/5 16:24:12

在这里插入图片描述
请添加图片描述

😶‍🌫️Take your time ! 😶‍🌫️
💥个人主页:🔥🔥🔥大魔王🔥🔥🔥
💥代码仓库:🔥🔥魔王修炼之路🔥🔥
💥所属专栏:🔥魔王的修炼之路–数据结构🔥
如果你觉得这篇文章对你有帮助,请在文章结尾处留下你的点赞👍和关注💖,支持一下博主。同时记得收藏✨这篇文章,方便以后重新阅读。


文章目录

  • 前言
  • 代码实现
    • 1、创建结构体
    • 2、初始化结构体
    • 3、销毁
    • 4、创建新结点
    • 5、入队列
    • 6、出队列
    • 7、队列成员个数
    • 8、队列是否为空
    • 9、队列最前面的元素数据
    • 10、队列最后面的元素数据
  • 总代码
    • Queue.h
    • Queue.c
    • Test.c
  • 总结

前言

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

在这里插入图片描述

代码实现

1、创建结构体

对于队列,需要创建两个结构体,第一个为结点的结构体,第二个是记录队列头、尾及元素个数的结构体,因为队列在入队时相当于尾插,如果不记录尾结点,需要一直遍历,这样效率低,所以在操作后直接记录尾结点,记录个数是因为方便其他函数操作,比如需要个数时,直接访问这个成员就行了,不需要再遍历一遍看看有几个,对于队列是否为空,也不需要判断指针是否为空,直接判断个数就行了。

代码实现:

#pragma once


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

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;//目的:要个数时,不需要遍历一遍,直接就能知道有几个。
}Queue;

2、初始化结构体

刚开始时怎样创建?是创建一个结构体指针然后接收在函数里开辟一块空间返回的结构体指针还是直接创建一个结构体,我们这里选择直接创建一个结构体,因为这个不像单链表一样,如果单链表没有元素,那么就是空,就没有结点一说,这个直接就一定不是空,因为我们操作的不是结点的结构体,而是记录队列的结构体,所以它永远不会是空,就不需要弄一个结构体指针再接收之类的操作了。

void QInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = NULL;
}

3、销毁

用完就需要销毁,防止内存泄漏。

void QDestroy(Queue* q)
{
	assert(q);
	while (q->head)
	{
		Queue* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->tail = NULL;//防止野指针
	q->size = 0;
}

4、创建新结点

入队列时需要创建新结点。

QNode* BuyNewnode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//检测是否开辟成功
	{
		perror("malloc error");
		assert(newnode);
	}
	newnode->data = x;
	newnode->next = NULL;
}

5、入队列

就像最开始的那个图一样,入队列相当于尾插。

//从后面进入,算是尾插。
void QPush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = BuyNewnode(x);
	if (q->head == NULL)//如果本来没有元素,需要让首尾指针都赋上这个结点;如果有元素,就管尾指针就行。
	{
		assert(q->head == q->tail);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

6、出队列

相当于头删。

//从前面出,算是头删。
void QPop(Queue* q)
{
	assert(q);
	assert(q->head && q->tail);//出队列时队列不能为空,如果不为空,那么首尾指针肯定都不为空。
	if (q->head->next == NULL)判断是否只有一个结点,如果只有一个,尾指针也要指向空,不然就会变成野指针。
	{
		assert()q->head==q->tail);//如果只有一个结点,那么首尾结点肯定相等。
		free(q->head);
		q->head = q->tail = NULL;
	}
	else
	{
		QNode* newhead = q->head->next;
		free(q->head);
		q->head = newhead;
	}
	q->size--;
}

7、队列成员个数

直接返回结构体里的size就行。

int QSize(Queue* q)
{
	assert(q);
	//int size = 0;
	//QNode* cur = q->head;
	//while (cur)
	//{
	//	cur = cur->next;
	//	size++;
	//}
	//return size;
	return q->size;
}

8、队列是否为空

直接判断size就行。

bool QEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}

9、队列最前面的元素数据

需要判断是否为空。如果为空就不能访问,不然越界。

QDataType QFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->data;
}

10、队列最后面的元素数据

需要判断队列是否为空,如果为空就不能访问,不然越界。

QDataType QBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->data;
}

总代码

Queue.h

Queue.h

#pragma once


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

typedef int QDataType;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;//目的:要个数时,不需要遍历一遍,直接就能知道有几个。
}Queue;

void QInit(Queue* q);

void QDestroy(Queue* q);

void QPush(Queue* q,QDataType x);

void QPop(Queue* q);

int QSize(Queue* q);

bool QEmpty(Queue* q);

QDataType QFront(Queue* q);

QDataType QBack(Queue* q);

Queue.c

Queue.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Queue.h"

void QInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = NULL;
}

void QDestroy(Queue* q)
{
	assert(q);
	while (q->head)
	{
		Queue* next = q->head->next;
		free(q->head);
		q->head = next;
	}
	q->tail = NULL;//防止野指针
	q->size = 0;
}

QNode* BuyNewnode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)//检测是否开辟成功
	{
		perror("malloc error");
		assert(newnode);
	}
	newnode->data = x;
	newnode->next = NULL;
}

//从后面进入,算是尾插。
void QPush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = BuyNewnode(x);
	if (q->head == NULL)//如果本来没有元素,需要让首尾指针都赋上这个结点;如果有元素,就管尾指针就行。
	{
		assert(q->head == q->tail);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;
}

//从前面出,算是头删。
void QPop(Queue* q)
{
	assert(q);
	assert(q->head && q->tail);//出队列时队列不能为空,如果不为空,那么首尾指针肯定都不为空。
	if (q->head->next == NULL)//判断是否只有一个结点,如果只有一个,尾指针也要指向空,不然就会变成野指针。
	{
		assert(q->head == q->tail);//如果只有一个结点,那么首尾结点肯定相等。
		free(q->head);
		q->head = q->tail = NULL;
	}
	else
	{
		QNode* newhead = q->head->next;
		free(q->head);
		q->head = newhead;
	}
	q->size--;
}

int QSize(Queue* q)
{
	assert(q);
	//int size = 0;
	//QNode* cur = q->head;
	//while (cur)
	//{
	//	cur = cur->next;
	//	size++;
	//}
	//return size;
	return q->size;
}

bool QEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}

QDataType QFront(Queue* q)
{
	assert(q);
	assert(q->head);
	return q->head->data;
}

QDataType QBack(Queue* q)
{
	assert(q);
	assert(q->tail);
	return q->tail->data;
}

Test.c

//测试队列
#define _CRT_SECURE_NO_WARNINGS 1

#include "Queue.h"


void print(Queue* q)
{
	while (!QEmpty(q))
	{
		printf("%d ", QFront(q));
		QPop(q);
	}
}

int main()
{
	Queue q;
	QInit(&q);
	QPush(&q, 0);
	QPush(&q, 1);
	QPush(&q, 2);
	QPush(&q, 3);
	QPush(&q, 4);
	QPush(&q, 5);
	QPop(&q);
	QPop(&q);


	print(&q);
	QDestroy(&q);
	return 0;
}

总结

结尾

  • 博主长期更新,博主的目标是不断提升阅读体验和内容质量,如果你喜欢博主的文章,请点个赞或者关注博主支持一波,我会更加努力的为你呈现精彩的内容。

🌈专栏推荐
😈魔王的修炼之路–C语言
😈魔王的修炼之路–数据结构初阶
😈魔王的修炼之路–C++
😈魔王的修炼之路–Linux
更新不易,希望得到友友的三连支持一波。收藏这篇文章,意味着你将永久拥有它,无论何时何地,都可以立即找到重新阅读;关注博主,意味着无论何时何地,博主将永久和你一起学习进步,为你带来有价值的内容。

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/516265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

No.065<软考>《(高项)备考大全》【专项3】《论文》

《论文》 1 论文部分相关1.1 考试相关1.2 考试核心相关1.3 历年考试分析1.4 复习建议1.5 评分标准1.5.1 评分的几个方面1.5.2 不及格的几种类型1.5.3 扣分项1.5.4 加分项 1.6 时间进度安排1.7 如何准备 2 必背核心知识 - 10大领域47个过程3 论文写作技巧3.1 论文架构3.2 论文题…

SpringBoot——引导类的简单介绍

简单介绍&#xff1a; 之前我们就说到过引导类&#xff0c;之不过当时就是简单的说了一下这个名字&#xff0c;让大家记住我们运行的程序的学名叫做引导类&#xff0c;但是我们并没有进入看过&#xff0c;介绍过它的作用&#xff0c;这次我们就来简单的介绍一下这个类的作用。…

[NLP] SentenceTransformers使用介绍

SentenceTransformers 是一个可以用于句子、文本和图像嵌入的Python库。 可以为 100 多种语言计算文本的嵌入并且可以轻松地将它们用于语义文本相似性、语义搜索和同义词挖掘等常见任务。 该框架基于 PyTorch 和 Transformers&#xff0c;并提供了大量针对各种任务的预训练模型…

STEP7-MicroWin SMART中修改变量注释的具体方法(绝对寻址+符号寻址)

STEP7-MicroWin SMART中修改变量注释的具体方法(绝对寻址+符号寻址) 如下图所示,我们可以在符号表中定义变量的符号名称以及注释信息, 使用时需注意以下事项: 1.在 STEP 7-Micro/WIN SMART 软件中,可以建立多个符号表,但不允许将相同的符号名多次用作全局符号赋值,在单…

1707_Python中的多成员处理

全部学习汇总&#xff1a; GreyZhang/python_basic: My learning notes about python. (github.com) 欢迎路过的YUAN类朋友们&#xff0c;希望我们能够相互交流共同成长。如有错误或者不足希望及时指点指出&#xff0c;不胜感激&#xff01;以下是我的联系方式&#xff1a; E…

Kali-linux识别活跃的主机

尝试渗透测试之前&#xff0c;必须先识别在这个目标网络内活跃的主机。在一个目标网络内&#xff0c;最简单的方法将是执行ping命令。当然&#xff0c;它可能被一个主机拒绝&#xff0c;也可能被接收。本节将介绍使用Nmap工具识别活跃的主机。 网络映射器工具Nmap Nmap是一个…

JavaScript经典教程(七)-- JavaScript中级

197&#xff1a;in、预解析、变量提升、对象引用、Date对象 1、预解析 即&#xff0c;把var的变量在&#xff0c;作用域下&#xff0c;提前&#xff1b; &#xff08;1&#xff09;JS代码运行原理 预先解析&#xff0c;JS第一次解析代码叫预解析。 JS本身会解析两次代码&a…

vue非单文件组件

非单文件组件指的是&#xff1a;一个文件中包含了多个组件。 Vue 中使用组件的三大步骤&#xff1a;1. 创建组件、2. 注册组件、3. 使用组件。 组件使用流程【第一步&#xff1a;创建组件】 利用 Vue.extend() 方法创建组件: // 第一步&#xff1a;创建 frameHead 组件 cons…

前端015_标签模块_删除功能

标签模块_删除功能 1、需求分析2、EasyMock 添加模拟接口3、Api 调用接口4、测试1、需求分析 当点击删除按钮后, 弹出提示框。点击确定后,执行删除并刷新列表数据 确认消息弹框参考:https://element.eleme.cn/#/zh-CN/component/message-box#que-ren-xiao-xi 2、EasyMock …

【AUTOSAR】【以太网】TCPIP

目录 一、概述 二、约束和假设 三、依赖模块 3.1 EthIf 3.2 EthSM 3.3 SoAd 3.4 KeyM 3.5 CSM 四、功能说明 4.1 系统扩展性 4.2 IPv4 4.2.1 IPv4 4.2.2 ARP 4.2.3 Auto-IP 4.2.4 ICMP 4.3 IPv6 4.4 IPSec 4.5 基于IP的协议 4.5.1 本地地址表 4.5.2 UDP 4…

音视频八股文(12)-- ffmpeg 音频重采样

1重采样 1.1 什么是重采样 所谓的重采样&#xff0c;就是改变⾳频的采样率、sample format、声道数等参数&#xff0c;使之按照我们期望的参数输出。 1.2 为什么要重采样 为什么要重采样&#xff1f;当然是原有的⾳频参数不满⾜我们的需求&#xff0c;⽐如在FFmpeg解码⾳频…

【C++初阶】类和对象(四)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C初阶】…

(二)zookeeper实战——zookeeper集群搭建

前言 本节内容我们主要介绍一下如何在centos系统下搭建一套高可用的zookeeper集群&#xff0c;zookeeper是我们常用的中间键之一&#xff0c;例如使用zookeeper实现分布式锁、Hadoop集群高可用、kafka集群高可用等等。我们以以下三台服务器为例&#xff1a; zookeeper服务器 I…

R语言tidyverse教程:ggplot2绘图初步

文章目录 基本流程渲染美化坐标轴设置 R语言系列&#xff1a; 编程基础&#x1f48e;循环语句&#x1f48e;向量、矩阵和数组&#x1f48e;列表、数据帧排序函数&#x1f48e;apply系列函数tidyverse&#xff1a;readr&#x1f48e;tibble 基本流程 ggplot2有其独特的绘图语…

【算法题】LCP 74. 最强祝福力场

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 题目&#xff1a; 小扣在探索丛林的过程中&#xff0…

MPLS格式和802.1q帧格式

一.MPLS IETF开发的多协议标记交换&#xff08;MPLS)把第2层的链路状态信息&#xff08;带宽、延迟、利用率等&#xff09;集成到第3层的协议数据单元中&#xff0c;从而简化和改进了第3层分组的交换过程 。理论上&#xff0c;MPLS支持任何第2层和第3层协议。MPLS包头的位置界…

web集群第一次作业

目录 一. 简述静态网页和动态网页的区别 二. 简述 Web1.0 和 Web2.0 的区别 三. 安装tomcat8&#xff0c;配置服务启动脚本&#xff0c;部署jpress应用。 一. 简述静态网页和动态网页的区别 1. 首先&#xff0c;两者的页面资源特征不同&#xff1a; 静态网页处理文件类型有…

【Linux】进程信号(完整版) --- 信号产生 信号保存 信号捕捉 可重入函数 volatile SIGCHLD信号等

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 文章目录 一、预备知识二、信号产生1. 通过终端按键产生信号1.1 signal()1.2 core dump标志位、核心存储文件 2.通过系统调用向进程发送信号3.由软件条件产生信号3.1 alarm函数和SIGALRM信号…

华为OD机试真题 Java 实现【知识图谱新词挖掘1】【2023Q1 100分】

一、题目描述 小华负责公司知识图谱产品&#xff0c;现在要通过新词挖掘完善知识图谱。 新词挖掘: 给出一个待挖掘文本内容字符串Content和一个词的字符串word&#xff0c;找到content中所有word的新词。 新词&#xff1a;使用词word的字符排列形成的字符串。 请帮小华实现新词…

【AI领域+餐饮】| 论ChatGPT在餐饮行业的应用展望

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…