数据结构与算法—稀疏数组和队列
目录
稀疏数组和队列
1.稀疏数组
所谓稀疏数组就是当数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以使用稀疏数组去压缩数据。OK,如果你不明白,那我们来看一个例子。
在一个五子棋中,有存盘和续上盘的功能
分析问题:因为该二维数组的很多默认值是 0,因此记录了很多没有意义的数据 > 稀疏数组
1.1 解决方法
思路
记录数组一共有几行几列,有多少个不同的值
把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的范围
应用实例
- 使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
- 把稀疏数组存盘,并且可以从新恢复为原来的二维数组
- 整体思路
1.2 代码实现
public class SparseArray { public static void main(String[] args) { //创建一个二维数组 //0:表示没有棋子 1表示黑子 2表示蓝子 int chessArr[][] = new int[11][10]; chessArr[1][2] = 1; chessArr[2][3] = 2; for(int[] row:chessArr){ for(int data:row){ System.out.printf("%d\t",data); } System.out.println(); } int[][] array = getSparseArray(chessArr); System.out.println("-------"); for(int i = 0 ; i< array.length;i++){ System.out.printf("%d\t%d\t%d\t\n",array[i][0],array[i][1],array[i][2]); } System.out.println("--------"); int[][] startArr = recovery(array); for(int[] row:startArr){ for(int data:row){ System.out.printf("%d\t",data); } System.out.println(); } } /** * 将普通数组转换为稀疏数组 * @param chessArr * @return */ public static int[][] getSparseArray(int[][] chessArr){ if(!checkIsRight(chessArr)){ return null; } //1.拿到数组后 首先获取元素的个数,然后才能建立稀疏数组 int sum = 0; for(int[] arr:chessArr){ for(int i:arr){ if(i != 0){ sum++; } } } //2.建立稀疏数组 int[][] sparseArr = new int[sum+1][3]; sparseArr[0][0] = chessArr.length; //行 sparseArr[0][1] = chessArr[0].length;//列 sparseArr[0][2] = sum; //元素个数 //3.数组存放 int count = 0; for(int i = 0; i <chessArr.length; i++ ){ for(int j = 0; j <chessArr[i].length;j++ ){ if(chessArr[i][j] != 0){ sparseArr[++count][0] = i;//行 sparseArr[count][1] = j;//列 sparseArr[count][2] = chessArr[i][j]; } } } return sparseArr; } /** * 将稀疏数组转回普通数组 * @param sparseArr * @return */ public static int[][] recovery(int[][] sparseArr){ if(!checkIsRight(sparseArr)){ return null; } //获取原数组的 行数和列数 并创建原数组 int arr[][] = new int[sparseArr[0][0]][sparseArr[0][1]]; for(int i = 1; i < sparseArr.length;i++){ arr[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2]; } return arr; } public static boolean checkIsRight(int[][] arr){ if(arr == null || arr.length <= 1 ){ return false; } return true; } }
2. 队列
- 队列是一个有序列表,可以用数组或链表来实现
- 遵循先入先出的原则
2.1 数组模拟队列
- 队列本身是有序列表,若使用数组的数据结构来存储队列的数据,则队列的数组声明如上图,其中maxSize是该队列的最大容量
- 因为队列的输出、输入分别从头尾端来处理,因此需要两个变量front及rear分别记录队列头尾端的下标,front会随着数据输出而改变,而rear会随着队列的输入而改变
- 当我们将数据输入队列时称为
addQueue
,addQueue
的处理有两个步骤:思路分析
(1) 将尾指针往后移:rear+1,当front == rear [空]
(2) 若尾指针rear小于队列的最大下标 maxSize - 1,则数据输入rear 所指的数组元素中,否则无法存入数据。
rear == maxSize - 1
代码实现
public class ArrayQueueDemo { public static void main(String[] args) { ArrayQueue queue = new ArrayQueue(10); queue.addQueue(1); queue.addQueue(2); queue.addQueue(3); queue.addQueue(4); queue.getQueue(); queue.showQueue(); } } //使用数组模拟队列-编写一个ArrayQueue类 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]; this.front = -1; this.rear = -1; } //判断队列是否已满 public boolean isFull(){ return rear == maxSize - 1; } //判断队列是否为空 public boolean isEmpty(){ return front == rear; } //添加数据到队列 public void addQueue(int n){ //判断队列是否满 if(isFull()){ System.out.println("队列已满"); return; } arr[++rear] = n; } //获取队列的数据,出队列 public int getQueue(){ if(isEmpty()){ throw new RuntimeException("队列已空"); } return arr[++front]; } //显示队列所有数据 public void showQueue(){ if(isEmpty()){ System.out.println("队列已空"); return; } for(int i = front+1 ;i <= rear;i++){ System.out.printf("arr[%d]=%d\n",i,arr[i]); } } }
2.2 数组模拟环形队列
之前实现的队列存在一个明显的问题,就是数组使用一次就不能再用了,出队列数据的位置始终空在那,没有达到一个复用的效果,因此我们要对这个队列进行一次优化,将此队列变成一个环形队列
思路
front 变量的含义做一个调整:front就指向队列的第一个元素,也就是 arr[front] 就代表队列的第一个元素,
front初始值 = 0rear 的变量含义做一个调整:rear指向最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值 = 0
当队列满时,条件是 (rear + 1) % maxSize == front 【满】
当队列为空的条件,rear == front 空
当我们这样分析,队列中有效的数据的个数 (rear + maxSize - front) % maxSize
我们就可以在原来的队列上修改得到 一个环形队列
代码实现
public class CircleArrayQueueDemo { public static void main(String[] args) { //测试一把 System.out.println("测试数组模拟环形队列的案例"); //创建一个环形队列 说明设置4,其队列数据最大是3 CircleArray queue = new CircleArray(4); char key = ' ';//接收用户输入 Scanner scanner = new Scanner(System.in); boolean loop = true; //输出一个菜单 while(loop){ 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):查看队列头的数据"); key = scanner.next().charAt(0); switch (key) { case 's': queue.showQueue(); break; case 'a': System.out.println("输出一个数字"); int value = scanner.nextInt(); queue.addQueue(value); break; case 'g': try { int res = queue.getQueue(); System.out.printf("取出的数据是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h'://查看队列头的数据 try { int res = queue.headQueue(); System.out.printf("队列头的数据是%d\n",res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'e'://退出 scanner.close(); loop = false; break; default: break; } } } } class CircleArray{ private int maxSize; private int front; private int rear; private int[] arr; public CircleArray(int maxSize){ this.maxSize = maxSize; arr = new int[maxSize]; } //判断队列是否已满 public boolean isFull(){ return (rear+1)%maxSize == front; } //判断队列是否为空 public boolean isEmpty(){ return rear == front; } //添加数据到队列 public void addQueue(int n){ //判断队列是否已满 if(isFull()){ System.out.println("队列满,不能加入数据"); return; } //直接将数据加入 arr[rear] = n; //将rear后移,这里必须考虑取模 rear = (rear+1)%maxSize; } //获取队列的数据 public int getQueue(){ //判断队列是否为空 if(isEmpty()){ //通过抛出异常 throw new RuntimeException("队列为空,不能取数据"); } int value = arr[front]; front = (front+1)%maxSize; return value; } //显示队列的所有数据 public void showQueue(){ //遍历 if(isEmpty()){ System.out.println("队列为空,没有数据"); return; } for(int i = front; i < front + size() ; i++){ System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]); } } //求出当前队列有效数据的个数 public int size(){ //加上maxSize 防止模出负数 因为这是一个环形队列 return (rear + maxSize - front)%maxSize; } //显示队列的头数据 public int headQueue(){ //判断 if(isEmpty()){ throw new RuntimeException("队列是空的,~没有数据"); } return arr[front]; } }
- 堆栈队列和数组-三元组稀疏矩阵
- hdu 1874 dijkstra 队列实现 比数组高效特别在稀疏图
- hdu 1874 dijkstra 队列实现 比数组高效特别在稀疏图
- java数据结构与算法之双向循环队列的数组实现方法
- 【数据结构与算法】数组应用3:稀疏矩阵压缩(Java实现)
- 考研数据结构与算法之堆栈的使用(三)数组实现的堆栈
- 用数组模拟 优先级队列
- 数组与STL实现单调队列的区别 POI2014 PTA-Little Bird
- Java用数组实现循环队列的示例
- 【栈和队列】一个数组实现两个栈
- 第三章-栈、队列、数组
- 数据结构与算法(7)--顺序队列
- 数据结构与算法-数组
- JAVA实现数组队列,循环数组队列,链式队列
- 使用队列对数组排列,基数排序
- 数据结构与算法--图的实现(邻接表、邻接矩阵、边的数组)
- tianchai 12012 解密QQ号 (数组实现队列)
- 创建自己的队列Queue底层实现利用数组
- C#集合类:动态数组、队列、栈、哈希表、字典
- 基于数组的有界阻塞队列ArrayBlockingQueue源码分析