二、稀疏数组和队列

news2024/11/30 0:28:13

稀疏数组

1、基本介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以用稀疏数组来保存该数组。

2、处理方式

  • 记录数组一共有几行几列,有多少个不同的值
  • 把具有不同值的元素的行列及值记录在一个小规模数组中,从而缩小程序的规模
    在这里插入图片描述

3、思路分析

3.1 二维数组转稀疏数组的思路
  • 遍历原始二维数组,得到有效数据的个数sum
  • 根据sum创建稀疏数组 int sparseArray[][] = new int[sum + 1][3];(稀疏数组固定是3列)
  • 将二维数组中的有效数据存放到稀疏数组中
3.2 稀疏数组转原始二维数组思路
  • 读取稀疏数组第一行数据,根据第一行数据创建原始数组,如:int chessArr[][] = new int[11][11];
  • 再读取稀疏数组后几行的数据,赋值给原始二维数组即可

在这里插入图片描述

4、代码实现

public class SparseArray {

	public static void main(String[] args) {
		//创建一个原始的二维数组 11*11
		//0 表示没有棋子 1 表示黑子 2表示蓝子
		int chessArr[][] = new int[11][11];
		chessArr[1][2] = 1;
		chessArr[2][3] = 2;
		System.out.println("====原始的二维数组====");
		printArray(chessArr);
		
		//将二维数组 转 稀疏数组
		//1、先遍历二维数组,得到非零数据的个数
		int sum = 0;
		for (int i = 0; i < chessArr.length; i++) {
			for (int j = 0; j < chessArr.length; j++) {
				if (chessArr[i][j] != 0) {
					sum++;
				}
			}
		}
		System.out.println("sum = " + sum);
		
		//2、创建对应的稀疏数组 (3列是固定的)
		int sparseArray[][] = new int[sum + 1][3];
		//给稀疏数组赋值
		sparseArray[0][0] = 11;
		sparseArray[0][1] = 11;
		sparseArray[0][2] = sum;
		
		//3、遍历数组,将非0的值放在sparseArray中
		int count = 0;//用于记录是第几个非0数据
		for (int i = 0; i < chessArr.length; i++) {
			for (int j = 0; j < chessArr.length; j++) {
				if (chessArr[i][j] != 0) {
					count++;
					sparseArray[count][0] = i;
					sparseArray[count][1] = j;
					sparseArray[count][2] = chessArr[i][j];
				}
			}
		}
		System.out.println("====得到的稀疏数组====");
		for (int i = 0; i < sparseArray.length; i++) {
			System.out.printf("%d\t%d\t%d\t\n", sparseArray[i][0],sparseArray[i][1],sparseArray[i][2]);
		}
		System.out.println();
		
		//将稀疏数组 转 原始二维数组
		// 1.先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
		int[][] chessArr2 = new int[sparseArray[0][0]][sparseArray[0][1]];
		
		// 2.读取稀疏数组的后几行数据(从第二行开始),并复制给原始的二维数组即可
		for (int i = 1; i < sparseArray.length; i++) {
			chessArr2[sparseArray[i][0]][sparseArray[i][1]] = sparseArray[i][2];
		}
		// 3.输出恢复后的二维数组
		 System.out.println("====恢复后的二维数组====");
	        printArray(chessArr2);
	}
	
	public static void  printArray(int[][] array) {
		for (int[] row : array) {
			for (int data : row) {
				System.out.printf("%d\t",data);
			}
			System.out.println();
		}
	}
}

输出结果如下:

原始的二维数组
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
sum = 2
得到的稀疏数组
11 11 2
1 2 1
2 3 2

恢复后的二维数组
0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0
0 0 0 2 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

练习

  1. 在代码实现的的基础上,将稀疏数组保存到磁盘上,比如map.data
  2. 恢复原来的数组,读取map.data进行恢复
/**
     * 存储稀疏数组,相邻数据使用\t划分
     * @param path 文件的存放路径
     * @param sparseArr 稀疏数组对象
     */
	public static void save(String path,int[][] sparseArr) {
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(path);
			for (int[] row : sparseArr) {
				fileWriter.write(row[0]+"\t" + row[1] + "\t" + row[2]);
				fileWriter.write("\r\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				fileWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
     * 读取二维稀疏数组,相邻数据使用\t划分
     * @param path 文件的存放路径
     * @return 二维的稀疏数组
     */
	public static void read(String path) {
		int[][] sparseArr = null;
		BufferedReader bufferedReader = null;
		try {
			bufferedReader = new BufferedReader(new FileReader(path));
			String lineStr = null;
			int lineCount = 0;
			while ((lineStr = bufferedReader.readLine()) != null ) {
				String[] tempStr = lineStr.split("\t");
				if (lineCount == 0) {
					// 稀疏数组的[0,2]位置记录了非0数据个数,所以稀疏数组大小为[Integer.parseInt(tempStr[2]) + 1][3]
					sparseArr = new int[Integer.parseInt(tempStr[2] ) +1 ][3];
				}
				sparseArr[lineCount][0] =Integer.parseInt(tempStr[0]); 
				sparseArr[lineCount][1] =Integer.parseInt(tempStr[1]); 
				sparseArr[lineCount][2] =Integer.parseInt(tempStr[2]); 
				lineCount++;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				bufferedReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

队列

  • 队列是一个有序列表,可以用数组或链表实现
  • 遵循先进先出的原则,即:先存入队列的数据,要先取出。后存入的要后取出。

1、数组模拟队列

  • 队列本身也是有序列表,若使用数组的结构来存储队列的数据,则队列数组的声明如下图,其中MaxSize为队列的最大容量
  • 因为队列的输出输入是分别从前后端来处理,因此需要两个变量front和rear分别记录前后端的下标,front会随着数据输出而改变,而rear会随着数据输入而改变
    在这里插入图片描述当我们将数据存入队列时称为”addQueue”,addQueue 的处理需要有两个步骤:思路分析
  1. 将尾指针往后移:rear + 1 , 当 rear==front 【空】
  2. 若尾指针 rear 小于队列的最大下标 MaxSize-1,则将数据存入 rear 所指的数组元素中,否则无法存入数据。 reatr==MaxSize - 1[队列满]

注:rear是队列最后(含), front是队列最前(不含)

2、代码实现

public class ArrayQueueDemo {

	public static void main(String[] args) {
		//创建一个队列
		ArrayQueue arrayQueue = new ArrayQueue(3);
		char key = ' ';// 接受用户输入
		Scanner scanner = new Scanner(System.in);
		boolean loop = true;
		System.out.println("s(show):显示队列");
		System.out.println("e(exit):退出程序");
		System.out.println("a(add):添加数据到队列");
		System.out.println("g(get):从队列取数据");
		System.out.println("h(head):查看队列头的数据");
		while (loop) {
			key = scanner.next().charAt(0);// 接收第一个字符
			switch (key) {
			case 's':
				arrayQueue.showQueue();
				break;
			case 'a':
				System.out.println("输入一个数:");
				int value = scanner.nextInt();
				arrayQueue.addQueue(value);
				break;
			case 'g':
				try {
					int res = arrayQueue.getQueue();
					System.out.printf("取出的数据是%d\n", res);
					continue;
				} catch (RuntimeException e){
					System.out.println(e.getMessage());
				}
				break;
			case 'h':
				try {
					int res = arrayQueue.headQueue();
					System.out.printf("队列头的数据是%d\n", res);
				} catch (RuntimeException e){
					System.out.println(e.getMessage());
				}
				break;
			case 'e':
				scanner.close();
				loop = false;
				break;

			default:
				break;
			}
		}
		System.out.println("程序退出");
	}
}

class ArrayQueue{
	private int maxSize;//表示数组的最大容量
	private int front; //队列头
	private int rear; //队列尾
	private int[] arr; //该数组用于存放数据,模拟队列

	public ArrayQueue(int maxSize) {
		this.maxSize = maxSize;
		arr = new int[maxSize];
		front = -1;// 指向队列头部,指向队列头部的数据的前一个位置
		rear = -1; // 指向队列尾,指向队列尾部的数据
	}

	/**
	 * 判断队列是否满
	 * @return
	 */
	public boolean isFull() {
		// 例如最大容量为5,rear是指向队列尾部数据,所以rear为4(maxSize - 1)的时候就为满了
		return rear == maxSize -1;
	}

	/**
	 * 判断队列是否为空
	 * @return
	 */
	public boolean isEmpty() {
		// 因为不是循环队列,头尾不相连,所以rear == front 时队列就为空
		return rear == front;
	}

	/**
	 * 添加数据到队列
	 * @param n
	 */
	public void addQueue(int n) {
		// 判断队列是否满
		if (isFull()) {
			System.out.println("队列满,不能加入数据~~");
			return;
		}
		rear++;
		arr[rear] = n;	
	}

	/**
	 * 数据出队列
	 * @return
	 */
	public int getQueue() {
		if (isEmpty()) {
			// 通过抛出异常
			throw new RuntimeException("队列为空,不能取数据~~");
		}
		front++;
		return arr[front];
	}

	/**
	 * 显示队列的所有数据
	 */
	public void showQueue() {
		if (isEmpty()) {
			System.out.println("队列空的,没有数据~~");
			return;
		}
		for (int i = 0; i < arr.length; i++) {
			System.out.printf("arr[%d] = %d\n", i, arr[i]);
		}
	}

	/**
	 * 显示队列的头数据,不是取数据而仅仅是显示
	 * @return
	 */
	public int headQueue() {
		if (isEmpty()) {
			// 通过抛出异常
			throw new RuntimeException("队列为空,不能取数据~~");
		}
		return arr[front + 1];
	}
}

4、此种实现方式存在缺陷和优化方案

  • 数组使用一次就不能使用了,没有达到复用的效果
  • 使用算法,改成一个环形的队列:取模%

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

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

相关文章

【OpenCV】红绿灯检测C++Demo实现

很久以来一直想实现红绿灯检测&#xff0c;今天它来了。 文章目录原理代码实现打包程序为exe原理 OpenCV好强&#xff0c;能够提取红绿灯的轮廓&#xff0c;并根据颜色空间判断红绿&#xff0c;不依赖深度学习算法也能做到可用的效果/demo。 红绿灯检测的基本步骤如下&#x…

20221103使用ffmpeg提取mp4视频的字幕

20221103使用ffmpeg提取mp4视频的字幕 2022/11/3 12:19 百度搜索&#xff1a; MP4 内置字幕 提取 https://www.6yxk.com/ruanjianjiaocheng/224526.html 提取mp4格式视频字幕的方法&#xff08;工具) ffmpeg -i D:\temp\001.mp4 -map 0:s:0 sub1.srt 百度搜索&#xff1a; ffmp…

web前端面试题附答案044 - vue获取param参数,有什么缺点吗?

看这个vue的图标像不像小时候看的《魔神坛斗士》身上的某个元素。真希望成年人的世界就像小时候一样简单快乐。 今天这道面试题主要围绕vue中获取param参数展开&#xff0c;看完本文你可以吸取到以下知识点 ◇ 首先是最基本的2中获取方式 ◇ 如果不用vue应该怎么获取&#xff…

Linux查看性能相关命令

#Linux查看性能相关命令 ##CPU性能 ###/cat/proc/cpuinfo 这个文件能够获取到物理cpu的数量,每个物理cpu的核心数,是否开启超线程等信息 物理cpu: 表示主板上实际存在的cpu数量 cpu核数: 单个cpu上可以处理数据的芯片组数量,如双核,四核等 逻辑cpu数量: 一般来说&#xff0c;…

数据链路层 随机接入-CSMA/CA协议

媒体接入控制-动态接入控制-随机接入 CSMA/CA协议 载波监听多址接入/碰撞避免CSMA/CA 既然CSMA/CA协议已经成功的应用于使用广播信道的有限局域网&#xff0c;那么同样使用广播信道的无线局域网能不能也使用CSMA/CD协议呢&#xff1f; 在无线局域网中&#xff0c;仍然可以使…

httpClient同步、异步性能对比

0、测试目的 同步阻塞模式下&#xff0c;如果服务端接口响应较慢&#xff0c;那会直接影响客户端接口请求的吞吐量&#xff0c;虽然可以通过在应用代码中通过异步线程的方式优化&#xff0c;但是会增加客户端的线程开销。所以考虑用异步模式来解决这个问题 因此测试时&#x…

【网络篇】如何给虚拟机添加网卡,设置固定ip

引言 基于Centos7&#xff0c;准备两台虚拟机作为rac服务器。 以Oracle rac集群的配置说明。 网络分配 根据子网地址&#xff0c;我们给虚拟机分配如下ip: 名称公网私网网关rac1192.168.189.10192.168.83.10192.168.189.2rac2192.168.189.11192.168.83.11192.168.189.2 说明…

从零到一手写迷你版Vue

Vue响应式设计思路 Vue响应式主要包含&#xff1a; 数据响应式监听数据变化&#xff0c;并在视图中更新Vue2使用Object.defineProperty实现数据劫持Vu3使用Proxy实现数据劫持模板引擎提供描述视图的模板语法插值表达式{{}}指令 v-bind, v-on, v-model, v-for,v-if渲染将模板转…

高性能服务器之Reactor设计

今天来针对上一节课讲的多路转接知识再进一步进行设计&#xff0c;Reactor是基于epoll的ET模式设计的&#xff0c;在现在的高校和企业中是广泛应用的&#xff0c;今天我们来实现一个简洁版&#xff0c;完整版博主可没那个实力~ 目录 基本原理 代码实现 epoll_server.cc A…

当面试官让我回答React和Vue框架的区别......

我们为什么需要错误边界 在React组件中可能会由于某些JavaScript错误&#xff0c;导致一些无法追踪的错误&#xff0c;导致应用崩溃。部分 UI 的 JavaScript 错误不应该导致整个应用崩溃。为此&#xff0c;React引入了错误边界(Error Boundary)的概念&#xff1a;可以捕获发生…

MySQL搭建主从复制流程及相关问题

目录一、关于主从复制1.1 关于主从复制1.2 应用场景1.3 优缺点1.4 原理二、配置主从复制2.1 同步各个服务器的时间2.2 修改主库&#xff08;M1&#xff09;配置2.3 主库&#xff08;M1&#xff09;为从库&#xff08;S1\S2&#xff09;增加账号2.3 查看主库&#xff08;M1&…

欢迎女神科学家颜宁回国,并祝她如愿以偿

目录1、女神科学家颜宁是谁2、颜宁在深圳人才论坛最新演讲&#xff0c;以及招聘邮箱3、颜宁微博回应4、结论与展望最近女神科学家颜宁回国了&#xff0c;整个科学界和中国都沸腾了&#xff0c;也上了热搜&#xff0c;成了热门话题&#xff0c;越来越多的海归精英选择回国 1、…

Python 和Java 哪个更适合做自动化测试?

很多小伙伴在功能测试行业工作了2、3年后&#xff0c;发现自己已经把功能测试做的非常好了&#xff0c;已经到职业发展和薪资发展的瓶颈期了&#xff0c;就想着学点东西&#xff0c;提升一下技能。 而对于功能测试升级来说&#xff0c;一般有这么3个主流的发展方向&#xff1a;…

事件/边沿检测--上升沿检测、下降沿检测

检测上升沿&#xff1a;&#xff08;从低到高的跳变 __| ) input sig_a; reg sig_a_d1; wire sig_a_risedge; alaways (posedge clk or negedge rstb) begin if(!rstb) sig_a_d1 < 1b0; else sig_a_d1 < sig_a; end assign sig_a_risedge sig_a & !sig_a_d1; …

【02】概率图模型在真实世界中的应用案例

概率图模型在真实世界中的应用案例 概率图模型有许多不同的实际应用。 为了激起大家对概率图模型的兴趣&#xff0c;也为了让大家能够对概率图模型有感性的认知&#xff0c;本章我会分享概率图模型的诸多实际应用案例。 文章目录图像中的概率模型图像生成图像修复图像降噪语言…

【Python百日进阶-WEB开发】Day171 - Django案例:03配置工程日志

文章目录八、配置工程日志8.1 目的和原因8.2 配置工程日志的步骤8.2.1 配置工程日志8.2.2 准备日志文件目录8.2.3 日志器记录器的使用8.2.4 Git管理工程日志九、配置前端静态文件9.1 准备静态文件9.2 指定静态文件的加载路径十、相关文档八、配置工程日志 8.1 目的和原因 目的…

什么是跨域?以及解决方案

现在的web项目&#xff0c;很多都是前后端分离&#xff0c;特别容易出现跨域问题 那么什么是跨域问题呢?本篇文章带你彻底从本质上弄明白什么是跨域问题以及如何解决 一、跨域有什么现象 首先我们看一下现象&#xff0c;如何出现的跨域问题。例&#xff1a; 前段&#xff1a…

【Linux】基础IO —— 上

&#x1f387;Linux&#xff1a;基础IO详解 博客主页&#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 看似不起波澜的日复一日&#xff0c;一定会在某一天让…

Web渗透测试攻防之浅述信息收集

前言 众所周知渗透测试的本质是信息收集&#xff0c;在渗透测试中信息收集的质量直接关系到渗透测试成果的与否。在对系统进行渗透测试前的信息收集是通过各种方式获取所需要的信息&#xff0c;收集的信息越多对目标进行渗透的优势越有利。通过利用获取到的信息对系统进行渗透…

Java Spring Cloud XVIII 之 Kafka I

Java Spring Cloud XVIII 之 Kafka I Kafka 1.Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台&#xff0c;由Scala和Java编写。该项目的目标是为处理实时数据提供一个统一、高吞吐、低延迟的平台。Kafka最初是由LinkedIn开发&#xff0c;并随后于2011年初开源…