日撸Java三百行(day18:循环队列)

news2024/9/22 21:21:38

目录

一、顺序队列与循环队列

二、代码实现

1.循环队列创建

2.循环队列遍历

3.循环队列入队

4.循环队列出队

5.数据测试

6.完整的程序代码

总结


一、顺序队列与循环队列

在昨天,我们提到队列实现除了采用链式存储结构,还可以采用顺序存储结构(因为队列是线性表,所以和线性表一样也有顺序、链式两种存储结构)。采用顺序存储结构的队列叫做顺序队列,它是用一组地址连续的存储单元依次存放从队头到队尾的队列元素,其中,需要附设头指针head和尾指针tail,分别指向队头元素和队尾元素。

为方便理解,下面我们用图示进行相关说明(假设队列的总存储空间TOTAL_SPACE = 5):

可以预测,如果我们在元素E之后再插入元素F,那么必然会插入失败,这是因为此时的尾指针tail已经达到队列的最大长度5,所以没办法继续插入元素。但事实上我们可以看到,此时下标为0的存储单元其实是空的,也就是说实际上此时的队列并没有满,这种现象就叫做“假溢出”。

简单来说,“假溢出”的原因就是队列在队头出队、队尾入队,从而造成队头出现空闲单元未被充分利用。为了解决这种“假溢出”现象,避免存储空间浪费,我们将队列的数组看作是头尾相接的循环结构,这种队列头尾相接的循环顺序存储结构就是循环队列,通过这种方式可以重用队头空闲下来的存储单元,如下图:

在循环队列中进行入队、出队操作,头尾指针的指向仍然要+1,不过不同的是,当头尾指针指向TOTAL_SPACE - 1(即头尾指针到达队列的最大长度处)时,此时再+1的结果就变成了头尾指针指向队列下标为0的地方。这种循环意义下的+1操作,可以用以下两种方式进行实现:

  • if( i == TOTAL_SPACE - 1) // i表示head或tail
       i = 0;
    else
       i++;
  • i = (i+1) % TOTAL_SPACE; // i表示head或者tail

对于第二种方式,很明显,当头尾指针指向TOTAL_SPACE - 1(即 i = TOTAL_SPACE - 1)时,i + 1就等于TOTAL_SPACE,进行整除运算后得到余数为0,所以i最后等于0;其余时候,i + 1均小于TOTAL_SPACE,所以整除后得到的余数即为i + 1本身,即i最后就等于i + 1。

通过上图,我们还可以发现,当循环队列为空或者已满时,头指针head均等于尾指针tail,这就会导致一个问题:当head = tail时,到底是判空还是判满?

可以通过以下三种方法来解决这个问题(在今天的代码实现中,我们用的是第二种方法):

  • 另外设置一个布尔变量,用于区别队空和队满。
  • 减少一个存储空间的使用,即把TOTAL_SPACE - 1个队列元素视为已满(也就是说,当下标为TOTAL_SPACE - 2的存储空间被占用,尾指针tail指向TOTAL_SPACE - 1时,视为已满),从而将队空和队满区别开来。因此,队空表示为 head = tail,队满表示为(tail + 1)% TOTAL_SPACE = head。

  • 设置一个计数器,用于记录当前队列中的元素个数。计数器初始值为0,新元素入队则计数器+1,元素出队则计数器-1,当计数器 = TOTAL_SPACE时,队满;当计数器 = 0时,队空。

二、代码实现

1.循环队列创建

首先,需要创建类,并定义成员变量、成员方法。由于循环队列是基于顺序表,所以这里大体上和顺序表的创建差不多,只需要再增加头指针head、尾指针tail的声明即可,如下:

public class CircleIntQueue {

	/**
	 * The total space. One space can never be used.
	 */
	public static final int TOTAL_SPACE = 10;

	/**
	 * The data.
	 */
	int[] data;

	/**
	 * The index for calculating the head. The actual head is head % TOTAL_SPACE.
	 */
	int head;

	/**
	 * The index for calculating the tail.
	 */
	int tail;

	/**
	 ******************* 
	 * The constructor
	 ******************* 
	 */
	public CircleIntQueue() {
		data = new int[TOTAL_SPACE];
		head = 0;
		tail = 0;
	} // Of the first constructor

2.循环队列遍历

    /**
	 *********************
	 * Overrides the method claimed in Object, the superclass of any class.
	 *********************
	 */
	public String toString() {
		String resultString = "";

		if (head == tail) {
			return "empty";
		} // Of if

		for (int i = head; i < tail; i++) {
			resultString += data[i % TOTAL_SPACE] + ", ";
		} // Of for i

		return resultString;
	} // Of toString

循环队列的遍历没什么好说的,也是通过重写toString()方法,基本上与之前顺序表的遍历一样。

3.循环队列入队

    /**
	 *********************
	 * Enqueue.
	 * 
	 * @param paraValue The value of the new node.
	 *********************
	 */
	public void enqueue(int paraValue) {
		if ((tail + 1) % TOTAL_SPACE == head) {
			System.out.println("Queue full.");
			return;
		} // Of if

		data[tail % TOTAL_SPACE] = paraValue;
		tail++;
	} // Of enqueue

由于顺序表的存储空间有上限,所以在入队之前需要先判断是否队满。根据之前的分析,得到队满判断条件为(tail + 1) % TOTAL_SPACE == head;确定队列未满后,进行入队操作,显然此时tail小于TOTAL_SPACE,所以tail % TOTAL_SPACE = tail,data[ tail % TOTAL_SPACE ]就是指已有队列元素后面第一个空的存储单元,将新元素赋给其即可完成入队,最后不要忘了更新尾指针。

4.循环队列出队

    /**
	 *********************
	 * Dequeue.
	 * 
	 * @return The value at the head.
	 *********************
	 */
	public int dequeue() {
		if (head == tail) {
			System.out.println("No element in the queue");
			return -1;
		} // Of if

		int resultValue = data[head % TOTAL_SPACE];

		head++;

		return resultValue;
	} // Of dequeue

出队只需判断是否队空,而队空的判断条件也十分简单,即head == tail;判断之后,开始出队,因为head小于TOTAL_SPACE,所以head % TOTAL_SPACE = head,data[ head % TOTAL_SPACE ]即为头指针指向的元素,也就是队头的第一个元素;最后,更新头指针,并返回删除的队列元素。

5.数据测试

方法创建完毕后,进行如下的数据测试: 

    /**
	 *********************
	 * The entrance of the program.
	 * 
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String args[]) {
		CircleIntQueue tempQueue = new CircleIntQueue();
		System.out.println("Initialized, the list is: " + tempQueue.toString());

		for (int i = 0; i < 5; i++) {
			tempQueue.enqueue(i + 1);
		} // Of for i
		System.out.println("Enqueue, the queue is: " + tempQueue.toString());

		int tempValue = tempQueue.dequeue();
		System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());

		for (int i = 0; i < 6; i++) {
			tempQueue.enqueue(i + 10);
			System.out.println("Enqueue, the queue is: " + tempQueue.toString());
		} // Of for i

		for (int i = 0; i < 3; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
		} // Of for i

		for (int i = 0; i < 6; i++) {
			tempQueue.enqueue(i + 100);
			System.out.println("Enqueue, the queue is: " + tempQueue.toString());
		} // Of for i
	} // Of main

6.完整的程序代码

package datastructure;

/**
 * Circle int queue.
 *
 *@auther Xin Lin 3101540094@qq.com.
 */
public class CircleIntQueue {

	/**
	 * The total space. One space can never be used.
	 */
	public static final int TOTAL_SPACE = 10;

	/**
	 * The data.
	 */
	int[] data;

	/**
	 * The index for calculating the head. The actual head is head % TOTAL_SPACE.
	 */
	int head;

	/**
	 * The index for calculating the tail.
	 */
	int tail;

	/**
	 ******************* 
	 * The constructor
	 ******************* 
	 */
	public CircleIntQueue() {
		data = new int[TOTAL_SPACE];
		head = 0;
		tail = 0;
	} // Of the first constructor

	/**
	 *********************
	 * Enqueue.
	 * 
	 * @param paraValue The value of the new node.
	 *********************
	 */
	public void enqueue(int paraValue) {
		if ((tail + 1) % TOTAL_SPACE == head) {
			System.out.println("Queue full.");
			return;
		} // Of if

		data[tail % TOTAL_SPACE] = paraValue;
		tail++;
	} // Of enqueue

	/**
	 *********************
	 * Dequeue.
	 * 
	 * @return The value at the head.
	 *********************
	 */
	public int dequeue() {
		if (head == tail) {
			System.out.println("No element in the queue");
			return -1;
		} // Of if

		int resultValue = data[head % TOTAL_SPACE];

		head++;

		return resultValue;
	} // Of dequeue

	/**
	 *********************
	 * Overrides the method claimed in Object, the superclass of any class.
	 *********************
	 */
	public String toString() {
		String resultString = "";

		if (head == tail) {
			return "empty";
		} // Of if

		for (int i = head; i < tail; i++) {
			resultString += data[i % TOTAL_SPACE] + ", ";
		} // Of for i

		return resultString;
	} // Of toString

	/**
	 *********************
	 * The entrance of the program.
	 * 
	 * @param args Not used now.
	 *********************
	 */
	public static void main(String args[]) {
		CircleIntQueue tempQueue = new CircleIntQueue();
		System.out.println("Initialized, the list is: " + tempQueue.toString());

		for (int i = 0; i < 5; i++) {
			tempQueue.enqueue(i + 1);
		} // Of for i
		System.out.println("Enqueue, the queue is: " + tempQueue.toString());

		int tempValue = tempQueue.dequeue();
		System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());

		for (int i = 0; i < 6; i++) {
			tempQueue.enqueue(i + 10);
			System.out.println("Enqueue, the queue is: " + tempQueue.toString());
		} // Of for i

		for (int i = 0; i < 3; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
		} // Of for i

		for (int i = 0; i < 6; i++) {
			tempQueue.enqueue(i + 100);
			System.out.println("Enqueue, the queue is: " + tempQueue.toString());
		} // Of for i
	} // Of main

} // Of class CircleIntQueue

运行结果

总结

循环队列是一种特殊类型的队列,它在传统顺序队列的基础上进行优化,通过“环形结构”充分利用存储空间,避免了空间浪费;虽然相比于链队列,循环队列似乎没有那么方便,不过在固定大小的缓冲区和任务调度等需要高效处理的数据流场景,循环队列还是非常适用的。昨天,我们学习了链队列,今天学习了循环队列,二者都是对于队列实现的模拟,这启示我们对于同一种逻辑结构,有时是可以采用不同的物理存储结构来实现的。

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

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

相关文章

数字电路波形图绘制工具WaveDrom简介

最近写东西的时候&#xff0c;需要画波形图&#xff0c;无意中找到了一蛮好用的工具&#xff1a;WaveDrom WaveDrom 是一个 JavaScript 应用程序。WaveJSON 是一种描述数字时序图的格式。WaveDrom 直接在浏览器内部渲染这些时序图。元素 “signal” 是一个 WaveLane 数组。每个…

NO.4 软件外包公司

今天我们来聊聊国内的四大软件外包公司。这些公司不仅在国内市场中占据重要地位&#xff0c;还对全球软件外包行业产生了影响。 部分数据来源网络排名&#xff0c;按照职位量、增长速度排名&#xff0c;排名仅供参考&#xff0c;去某家公司一定要多方位参考&#xff0c;比如企查…

uniapp基础知识【搬代码】

基础知识 HTML、css、javaScript&#xff08;ES6&#xff09; HTML结构 1.View 类似于传统html中的div&#xff0c;用于包裹各种元素内容。 2.text文本 3.swoper 4.image 5.video 6.button 7.input <template><!-- <view class"content"><imag…

泛微E-office 10 schema_mysql接口敏感信息泄露漏洞复现 [附POC]

文章目录 泛微E-office 10 schema_mysql接口敏感信息泄露漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现泛微E-office 10 schema_mysql接口敏感信息泄露漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内…

两篇论文同时获最佳论文荣誉提名,SIGGRAPH上首个Real-Time Live的中国团队用生成式AI创建3D世界

专注于计算机图形学的全球学术顶会 SIGGRAPH&#xff0c;正在出现新的趋势。 点击访问我的技术博客https://ai.weoknow.comhttps://ai.weoknow.com 在上周举行的 SIGGRAPH 2024 大会上&#xff0c;最佳论文等奖项中&#xff0c;来自上海科技大学 MARS 实验室的团队同时拿到两篇…

HTML表单元素

HTML表单元素 表单把用户的信息发给服务器。 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title> </head><body><form class"stylin_form1" action"process_form.php" met…

uni-app开发微信小程序注意事项,不要用element-ui

前端扩展组件千万不要用element-ui&#xff0c;开发的时候不报错&#xff0c;发布的时候会报错无法发布。 可以用vant weapp【注意是weapp】 iView weapp 附上hbuilder官方文档 组件的概念 | uni-app官网 (dcloud.net.cn)

git-贮藏区打补丁

1.显示所有贮藏 git stash list 2.将贮藏区的修改打补丁 git stash show -p stash{0} > patchName.patch commit打补丁 git 生成补丁文件及打补丁_git 生成指定目录补丁-CSDN博客 git patch的使用方法_git pattch-CSDN博客

「MyBatis」数据库相关操作

MyBatis 简介 MyBatis 是⼀个持久层框架&#xff0c;用于简化 JDBC 的开发 持久层指的就是持久化操作的层&#xff0c;通常指数据访问层 (dao)&#xff0c;是用来操作数据库的 Mapper 注解的接口表示该接口是 MyBatis 中的 Mapper 接口 回顾一下之前提到过的图 简单来说&…

如何选用合适的开源知识管理系统?10款软件推荐

国内外主流的10款开源知识管理软件对比&#xff1a;PingCode、Worktile、DokuWiki、MediaWiki、GitBook、Nuclino、Think、TiddlyWiki、AFFiNE、Foam。 在管理知识的广阔天地中&#xff0c;选择合适的工具可能会让你感到头痛。开源知识管理软件以其灵活性和成本效益在行业内脱颖…

Java设计模式-单例模式最佳实践

1. 单例模式简介 Java 单例模式是四大设计模式之一&#xff0c;属于创建型设计模式。从定义上看&#xff0c;它似乎是一种简单的设计模式&#xff0c;但在实现时&#xff0c;如若不注意&#xff0c;它会带来很多问题。 在本文中&#xff0c;我们将了解单例设计模式原则&#…

使用 GPU 加速的 XGBoost 预测出租车费用

目录 XGBoost GPU 加速的 XGBoost 用例数据集示例 将文件中的数据加载到 DataFrame 定义特征数组 保存模型 总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff0c; 可以当故事来看&#xf…

小智纯前端js报表实战5-绝对坐标-横向扩展

绝对坐标-横向扩展 概述 绝对坐标-横向扩展&#xff1a;绝对坐标定位 层次坐标是实现复杂报表的一个重要功能。 在进行小智报表模板设计时&#xff0c;单元格尚未进行扩展&#xff0c;但是有些时候需要获取扩展后的单元格并进行计算。例如&#xff0c;A1单元格扩展成A1-D1&am…

VUE+Spring前后台传值的坑,后台接收的String参数在末尾会出现 “=”

一、问题 VUESpringBoot做增删改查时&#xff0c;前端使用axios.post发起请求&#xff0c;传输主键字符型参数 taskId 到后台&#xff0c;后台再进行删除处理。 实际过程中发现后台拿到的数据再末尾多了一个等号&#xff0c;但是通过console.log(taskId)前台打印参数是正常的…

巴洛克风格的现代演绎,戴上亚法银耳机,感受古典雕花与现代声学的碰撞

flipears耳机品牌以其独特的风格、精细的配置和卓越的音质在耳机市场中很受欢迎&#xff0c;像是我最近用过的一款Artha Argentum亚法银&#xff0c;就采用了纯银外壳&#xff0c;而且用料扎实&#xff0c;具有出众的声学表现&#xff0c;带来了更干净清澈的声底。内在配置方面…

[Linux] LVM挂载的硬盘重启就掉的问题解决

问题&#xff1a;系统重启后挂在逻辑卷的盘会掉&#xff08;必现&#xff09; 环境&#xff1a;SUSE Linux 11 SP4 原因&#xff1a;boot.lvm是关闭的 解决&#xff1a;boot.lvm设置开启 参考资料&#xff1a; linux下lvm状态Not avaliable问题排查及处理(常见Suse操作系统…

使用ubuntu串口数据收和发不一致问题

串口配置 使用virtual Serial Port Driver Pro模拟串口两个串口&#xff0c;com2和com3&#xff0c;使用默认配置&#xff1b;通过virtual box 串口映射功能&#xff0c;在Ubuntu里使用CuteCom打开com2接受和发送数据&#xff0c;在windows里使用com3发送和接收数据。 遇到问…

24/8/9算法笔记 随机森林

"极限森林"&#xff08;Extremely Randomized Trees&#xff0c;简称ERT&#xff09;是一种集成学习方法&#xff0c;它属于决策树的变体&#xff0c;通常被归类为随机森林&#xff08;Random Forest&#xff09;的一种。极限森林的核心思想是在构建决策树时引入极端…

空间推理验证码的介绍!

空间推理验证码 ​是一种验证码形式&#xff0c;‌旨在通过要求用户解决一些视觉或空间推理问题来区分计算机和人类用户。‌这种验证码形式要求用户通过完成一些视觉或空间推理任务来证明他们是真实的人类用户&#xff0c;‌而不是计算机程序。‌空间推理验证码通常涉及一些图…

智慧交通:将物联网与人工智能完美融合

智慧交通是当今社会面临的一个重要挑战&#xff0c;也是人们生活质量提高的一个重要方面。通过将物联网技术与人工智能相结合&#xff0c;我们能够实现智慧交通系统的全面升级和优化&#xff0c;为人们带来更加便捷、高效和安全的出行体验。 在智慧交通领域&#xff0c;物联网…