所谓稀疏数组就是当数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。所以形成内存空间的浪费,为了节省内存空间,而且不影响数组中原有的内容值,咱们可使用稀疏数组去压缩数据。OK,若是你不明白,那咱们来看一个例子。小程序
在一个五子棋中,有存盘和续上盘的功能数组
分析问题:由于该二维数组的不少默认值是 0,所以记录了不少没有意义的数据 > 稀疏数组数据结构
思路oop
记录数组一共有几行几列,有多少个不一样的值测试
把具备不一样值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的范围优化
应用实例this
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; } }
addQueue
,addQueue
的处理有两个步骤:思路分析(1) 将尾指针日后移:rear+1,当front == rear [空]spa
(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]); } } }
以前实现的队列存在一个明显的问题,就是数组使用一次就不能再用了,出队列数据的位置始终空在那,没有达到一个复用的效果,所以咱们要对这个队列进行一次优化,将此队列变成一个环形队列
思路
front 变量的含义作一个调整:front就指向队列的第一个元素,也就是 arr[front] 就表明队列的第一个元素,
front初始值 = 0
rear 的变量含义作一个调整: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]; } }