数据结构之实现队列

news2024/12/24 3:54:32

文章目录

  • 前言
  • 1.队列的相关介绍
    • 1.队列的定义
    • 2.队列的实现方式
  • 2.队列具体实现
    • 1.队列声明定义
    • 2.队列的接口
      • 1.初始化接口
      • 2.数据的插入和删除
      • 3.获取队头元素和队尾元素
      • 4.获取队列元素个数和队列判空以及队列
  • 3.总结

前言

之前谈到了栈的实现,现在来说说另一种数据结构——队列的实现。队列这种结构也是线性的,本文将会对队列的实现进行简单讲解,为以后学习其他数据结构打下牢固的基础。


1.队列的相关介绍

1.队列的定义

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

队列和栈这种结构有点相反,栈只能再一端入数据和出数据,队列的一端入数据,另一端出数据。队列可以形象的理解为排队做核酸。队头的人做完核酸就走了,相当于队列出数据,后面来做核酸的人,接着队尾按次序排队就相当于队列入数据。
在这里插入图片描述


2.队列的实现方式

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

队列因为一端出数据,另一端进数据。如果采用数组来实现肯定是代价更大一点的,因为在出数据以后需要挪动数据,更新队头的元素,如果采用链表来实现,就不用担心这个问题了。插入数据和删除数据只需要更新头节点和尾节点即可。


2.队列具体实现

1.队列声明定义

刚才提到了使用链表来实现队列比较好,队列采用链表实现的话,那么队列的每个数据是存储在节点中的,那么就定义创建队列节点结构体,有了节点,相当于队列的身体创建好了,那么怎么维护这个队列呢?我们在创建队列结构体,队列结构体来表示一个完整的队列,用于维护整个队列。

代码示例

typedef int QDataType;
//定义队列节点
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QueueNode;
//定义队列
typedef struct Queue
{
	QueueNode* head;//维护队头
	QueueNode* tail;//维护队尾
	int sz;//记录队列元素个数
}Queue;

队列节点的结构和普通单链表的节点一样,队列结构体中成员有头节点和尾节点分别用来维护队列头和队列尾。同时,还有一个整型变量来用来记录队列中数据个数。为啥不像链表那样直接只定义节点,为啥还要单独创建一个队列结构体呢?因为队列是需要访问队尾和队头元素的而且队头和队尾是需要更新的,如果只是单单定义节点,在访问队尾和更新队尾时,是要进行遍历的,这显得不是和方便。虽然双向循环链表可以快速找到头和尾,但是也略显麻烦了,如果是定义了队列结构,用结构中的成员来维护队尾队头,这个队列就被很好的管理起来了,而且很方便,也不是太繁琐。


2.队列的接口

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);// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
void QueueDestroy(Queue* q);// 销毁队列

这些接口和栈的接口其实都是差不多的,多了一个获取队头元素的接口,栈只有获取栈顶元素的接口。*


1.初始化接口

void QueueInit(Queue* q)//初始化队列
{
	assert(q);
	q->head = NULL;
	q->tail = NULL;
	q->sz = 0;
	return;
}

初始化的时候队头和队尾都是空,sz也位空。


2.数据的插入和删除

数据的插入就从队尾开始插入,用尾插处理就好了,数据的删除就是从队头出了数据后要将原队列头节点给删除了,并且更新队头。

Push代码示例

void QueuePush(Queue* q, QDataType data)//队尾入列
{
	    assert(q);
		QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
		if (newnode==NULL)
		{
			perror("QueuePush:");
			exit(-1);
		}
		newnode->data = data;
		newnode->next = NULL;
		if (q->head == NULL)
		{
			q->head = q->tail = newnode;//只有一个队列节点时,头尾都是自己
			
		}
		else  
		{   
			q->tail->next = newnode;
			q->tail = newnode;
			
		}
		q->sz++;
		return;
}

队尾插入就是尾插,当头的空的时候单独处理一下就好了。因为只有这个接口需要malloc节点,所以就没有单独封装一个接口来实现节点空间的申请。每次增加一个节点时,sz自增计数。


Pop代码示例

void QueuePop(Queue* q)//队头元素出列
{
	assert(q);
	assert(!QueueEmpty(q));
	if (q->head->next == NULL)//队列只有一个节点
	{   free(q->head);
		q->head = NULL;
		q->tail=NULL;
	}
	else
	{
		QueueNode* del = q->head;
		q->head = q->head->next;
		free(del);
	}
	q->sz--;
	return;
}


删除数据就是释放队列的原头节点,在释放之前应该先将头节点进行更新,因为队列是从队头开始出数据,所以只用队头节点进行释放。但是要注意一点当队列的节点只有一个时,应该单独处理一下,因为如果不处理头节点指向的空间已经被free释放掉了,head->next肯定会访问已经释放的空间,这样就会引发程序崩溃。单独处理时我们直接将这个节点释放后,队头和队尾给置为空就可以了。同时每次删除以后sz需要自减一下。


3.获取队头元素和队尾元素

队头和队尾的元素的获取就很简单了,队列结构中有头指针和尾指针来维护队头和队尾。这样就可以直接访问队头节点和队尾节点了。

队头元素的获取 代码示例

QDataType QueueFront(Queue* q)//获取队列队头元素
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->data;
}

直接返回头队列中头节点指向的data值就好了,但是要注意当队列为空的时候就不能出数据了,需要进行断言,关于这个判空函数下面将会介绍。


队列尾元素的获取 代码示例

QDataType QueueBack(Queue* q)//获取队列队尾元素
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}

这个和获取队头元素基本上一样,将头指针改成尾指针就好了。这也说明了我们将队列的结构设计成这样的好处,访问头尾位置的时候非常方便。


4.获取队列元素个数和队列判空以及队列

获取元素个数 代码示例

int QueueSize(Queue* q)//获取队列元素个数
{   
	assert(q);
	return q->sz;
}

这个直接返回sz即可,sz就是表示的队列元素个数。


队列判空 代码示例

int QueueEmpty(Queue* q)// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
{
	assert(q);
	return q->sz==0 ;
}

如果sz为0就是队列为空,这个用布尔值判断比较好,之前也说过C语言使用布尔值引入相应的头文件即可。因为我们是通过sz的值判断队列是否为空,使所以在Pop单独处理一个节点时,尾指针不用置为空也可以。不过为了养成良好的代码习惯,最好还是置为空。


销毁队列 代码判空

这个就是还是挨个遍历free释放即可。

队列销毁 代码示例

void QueueDestroy(Queue* q)// 销毁队列
{
	assert(q);
	QueueNode* cur = q->head;
	while (cur)
	{
		QueueNode* Next = cur->next;
		free(cur);
		cur = Next;
	}
	q->head = NULL;
	q->tail = NULL;
	q->sz = 0;
	return;
}

这个实现起来也是比较简单的


3.总结

在我们学习实现链表后,这个队列和栈的实现总体来说没那么难,很多接口的实现有都有些相似之处。

学习是一个积累过程,编程是需要不断练习的,熟能生巧!

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

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

相关文章

[hadoop全分布部署]虚拟机Hadoop集群配置/etc/hosts、配置无密码登录(SSH)

👨‍🎓👨‍🎓博主:发量不足 个人简介:耐心,自信来源于你强大的思想和知识基础!! 📑📑本期更新内容:虚拟机Hadoop集群配置/etc/hosts…

Centos 7下安装php+mysql+nginx+wordpress教程新版

安装zsh+oh-my-zsh 安装zsh的原因是因为不喜欢自带的ssh工具,感觉没有这个好用,我最常用的就是记忆功能,比如输入某个字母,按上下键会自动补全已经使用过的命令,安装也很简单,一条命令搞定,他的扩展也很多,这里只讲最简单的安装,当然也可以不需要安装。 执行yum inst…

Linux基本指令

这一章我们将讲解在Linux系统下,一些基本指令的用法和功能. 后面有一些重要的指令我们将单独讲解. 目录 ls 指令 pwd 指令 cd 指令 touch 指令 mkdir 指令★ rmdir 指令 && rm指令★ man 指令★ cp 指令 ★ mv 指令★ cat && tac指令 e…

nodejs+vue毕业生就业知道信息平台系统

大学毕业生招聘系统分三个身份登录,一个学生,一个管理员,一个是企业用户。学生可以注册登录管理自己的简历,应聘职位,企业用户可以发布招聘,收到应聘信息,查看学生简历,收藏学生简历,而管理员可以修改任何信息。 管理员模块有: 1.…

【8-数据库表结构的创建后台管理系统的搭建】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了,请点击这里!】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

OPSS-PEG-N3,OPSS-PEG-azide,巯基吡啶-PEG-叠氮化学试剂供应

1、名称 英文:OPSS-PEG-N3,OPSS-PEG-azide 中文:巯基吡啶-聚乙二醇-叠氮 2、CAS编号:N/A 3、所属分类:Azide PEG Orthopyridyl disulfide (OPSS) PEG 4、分子量:可定制,2K 巯基吡啶-PEG-叠…

海量短视频打标问题之多模态机器学习

引言 接着讲,既然我们是给视频打标签,那么肯定就不能只局限于图像上做文章。视频文件包含的信息很多,一个短视频除了有一帧一帧的图像,还有声音信息,甚至还有字幕或者用户打的标签和文字评论之类的这些信息&#xff0…

第2关:ZooKeeper配置

配置项介绍 基础配置 tickTime:Client和Server通信心跳数。 Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每隔tickTime的时间就会发送一个心跳。tickTime以毫秒为单位。 initLimit:LF初始通信时限。 集群中的followe…

muduo库的高性能日志库(二)——LogStream文件

目录概述FixBuffer类(模板缓冲区)LogStream类LogStream.hLogStream.cc十进制整数转化为字符串地址(指针)数据转换为16进制字符串浮点类型数据转化为字符串Fmt类C单元测试框架(简略)什么是单元测试常用测试工…

用了CDN就一定比不用更快吗?

对于开发同学来说,CDN这个词,既熟悉又陌生。 平时搞开发的时候很少需要碰这个,但却总能听到别人提起。 我们都听说过它能加速,也大概知道个原因,但是往深了问。 用了CDN就一定比不用更快吗? 就感觉有些…

C++ Reference: Standard C++ Library reference: Containers: deque: deque: cbegin

C官网参考链接&#xff1a;https://cplusplus.com/reference/deque/deque/cbegin/ 公有成员函数 <deque> std::deque::cbegin const_iterator cbegin() const noexcept;返回指向开始的常量迭代器 返回指向容器第一个元素的const_iterator。 const_iterator是指向const内…

大一新生HTML期末作业,实现登录页面

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

js+贝塞尔曲线+animate动画

文章目录一 介绍二 示例1阶贝塞尔曲线2阶贝塞尔曲线3阶贝塞尔曲线:4/n阶贝塞尔曲线三 封装和使用bezier.jsApp.jsxApp.scss一 介绍 贝塞尔曲线(Bzier curve)&#xff0c;又称贝兹曲线或贝济埃曲线&#xff0c;是应用于二维图形应用程序的数学曲线。 下面是我们最常用到bezier曲…

【7-创建商城系统的子模块并将修改后的信息使用Git提交到Gitee上】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

测试.net开源敏感词检测库ToolGood.Words

微信公众号“DotNet”看到介绍.net开源敏感词检测库ToolGood.Words的文章《.NET Core一款高性能敏感词检测开源库》&#xff0c;根据参考文献2中的测试&#xff0c;该库的检测效率比C#自带的正则效率高8.8倍&#xff0c;如果数量量越大性能优势越明显。   ToolGood.Words的Gi…

英文Paper写作如何尽量避免抄袭?

说到英文Paper的写作&#xff0c;我们就不得不提到reference&#xff0c;中文称之为引用。在国外&#xff0c;合理正确的利用reference非常重要&#xff0c;国外对于知识产权的保护很严格&#xff0c;对于抄袭行为也是不能容忍的。学术表现差或是学术不诚实问题是造成学生被开除…

4.构造类型,类型转换

构造类型 由若干各个相同或不同类型的数据构成的集合&#xff0c;这种集合类型被称为构造类型 例&#xff1a;int a[10]; 数组、结构体、共用体、枚举 类型转换 数据有不同的类型&#xff0c;不同类型数据之间进行混合运算时必然涉及到类型转换的问题。 转换的方式有两种&am…

使用verdaccio搭建私有组件库

前言 最近公司需要根据现有的公用组件搭建一套私有组件库&#xff0c;方便其他项目使用&#xff0c;然后经过一系列尝试和走了许多坑&#xff0c;终于搭建成功了&#xff0c;这里记录下搭建步骤&#xff0c;希望对你有些帮助。 为什么选择verdaccio 由于公司组件库越来越多&…

ZZNUOJ_Java软件的下载安装和写代码

ZZNUOJ_Java软件的下载安装和写代码一、Java软件myeclipse图标二、下载安装的步骤三、使用myeclipse软件1、创建项目名和类名的步骤2、写代码和运行结果一、Java软件 myeclipse图标 二、下载安装的步骤 第一步骤&#xff1a;下载myeclipse&#xff1a;myeclipse 第二步骤&…

怎么把旧电脑的用户配置文件迁移到新电脑

您购买了一台新笔记本电脑&#xff0c;但不想花大量时间重新下载、编辑、备份旧电脑上的所有文件&#xff0c;也不想重新安装常用的软件&#xff0c;更不想重新配置电脑账户&#xff0c;那么&#xff0c;应该怎么把旧电脑的用户配置文件迁移到新电脑&#xff1f; 一、如何迁移用…