本篇学习内容跟随韩顺平老师的数据结构与算法视频,是一篇持续更新的文章。
一边学习一边更新(主要是督促自己打卡学习嘎嘎)
数据结构与算法我来啦~~~
奥利给大家一起加油冲冲冲!!!
稀疏数组
内容
当一个数组中的大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。
稀疏数组的处理方法:
-
记录数组一共有几行几列,有多少个不同的值
-
把具有不同值的元素的行列记录在一个小规模的数组中,从而缩小程序的规模。
整体思路:
二维数组——>稀疏数组
稀疏数组第一行三个值分别为:二维数组的行、二维数组的列,二维数组中不同值的个数。所以先遍历二维数组,获取稀疏数组第一行的值
根据sum的值创建稀疏数组
sparseArr int[sum+1][3];
遍历二维数组,将有效值放入稀疏数组中。
稀疏数组——>二维数组
根据稀疏数组第一行的值创建对应行列的二维数组
遍历稀疏数组,将有效值放入二维数组中
应用实例:
棋盘或者地图等
代码实现
package com.yan.sparseArray; public class SparseArray { public static void main(String[] args) throws Exception { // 生成二维数组 int[][] chessArr1 = new int[11][11]; chessArr1[1][2] = 1; chessArr1[2][3] = 2; // 原始数组 System.out.println("原始数组为:"); for (int i = 0; i < 11; i++) { for (int j = 0; j < 11; j++) { System.out.print(chessArr1[i][j] + "\t"); } System.out.println(); } // 二维数组转稀疏数组 int sum = 0; for (int i = 0; i < chessArr1.length; i++) { for (int j = 0; j < chessArr1[i].length; j++) { if (chessArr1[i][j] != 0) { sum++; } } } // 稀疏数组 int count = 0; int[][] chessArr2 = new int[sum + 1][3]; chessArr2[0][0] = chessArr1.length; chessArr2[0][1] = chessArr1[1].length; chessArr2[0][2] = sum; for (int i = 0; i < chessArr1.length; i++) { for (int j = 0; j < chessArr1[i].length; j++) { if (chessArr1[i][j] != 0) { count++; chessArr2[count][0] = i; chessArr2[count][1] = j; chessArr2[count][2] = chessArr1[i][j]; } } } System.out.println("稀疏数组:"); for (int i = 0; i < sum + 1; i++) { for (int j = 0; j < 3; j++) { System.out.print(chessArr2[i][j] + "\t"); } System.out.println(); } System.out.println("============="); // 稀疏数组转二维数组 int[][] chessArr3 = new int[chessArr2[0][0]][chessArr2[0][1]]; int count2 = 1; for (int i = 1; i < chessArr2.length; i++) { chessArr3[chessArr2[i][0]][chessArr2[i][1]] = chessArr2[i][2]; } System.out.println("================"); System.out.println("二维数组:"); for (int i = 0; i < chessArr3.length; i++) { for (int j = 0; j < chessArr3[i].length; j++) { System.out.print(chessArr3[i][j] + "\t"); } System.out.println(); } } }
队列
-
允许一端插入(队尾),一端删除(队首)的有序列表,可以用数组或链表实现
-
先入先出原则FIFO
一次性队列
代码实现
package com.yan.ArrayQueue; public class ArrayQueueDemo { public static void main(String[] args) { //测试part ArrayQueue queue = new ArrayQueue(3); Scanner sc = new Scanner(System.in); boolean loop = true; while (loop) { System.out.println("a(add):添加数据"); System.out.println("g(get):获取数据"); System.out.println("h(head):获取头数据"); System.out.println("s(show):显示所有数据"); char cc = sc.next().charAt(0); switch (cc) { case 'a': System.out.println("请输入一个数:"); int num = sc.nextInt(); queue.addQueue(num); break; case 'g': try { int res = queue.getQueue(); System.out.println("去除的数据是:" + res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 'h': try { int res = queue.getQueue(); System.out.println("头数据为:" + res); } catch (Exception e) { System.out.println(e.getMessage()); } break; case 's': queue.showQueue(); break; default: sc.close(); loop=false; break; } } System.out.println("程序退出!"); } } //使用数组模拟队列 class ArrayQueue { private int maxSize;//表示数组的最大容量 private int front;//队列头 private int rear;//队列尾 private int[] arr;//用于存放数据的数组,模拟队列 // 创建数组 public ArrayQueue(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; front = -1;// front指向队列头的前一个位置 rear = -1;//rear指向队列的最后一个数据 } // 判空 public boolean isEmpty() { return front == rear; } // 判满 public boolean isFull() { return rear == maxSize - 1; } // 添加操作(添加一个数据) public void addQueue(int n) { if (isFull()) { System.out.println("队列满,不能加入数据!"); return; } rear++; arr[rear] = n; } // 出队列操作 public int getQueue() { if (isEmpty()) { throw new RuntimeException("队列空,不能取数据"); } front++;//front开始为-1,所以先+1 return arr[front]; } // 得到头数据 public int headQueue() { if (isEmpty()) { throw new RuntimeException("队列空,没有头数据"); } return arr[front + 1]; } // 显示队列 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]); } } }
问题分析:
Q:当队尾指针到达尾部时,Rear不能后移了,空间被浪费了怎么办?
A:让队尾指针接着向前走(环形队列%)
循环队列
头尾相连的循环可以避免假溢出(即rear超过了maxsize-1,但前面还有空间),头尾相接的顺序存储结构称为循环队列。
Q:此时rear==front为队列满了的时候,但是和队列空时的判断条件一样了怎么办?/(ㄒoㄒ)/~~
A:此时我们选择保留一个元素空间。即队列满时,数组中还有一个空闲单元。如下图:
Q:此时又出现了一个问题,那rear所在的下标时而大于front,时而小于front,这怎么判断?
A:引入取模运算符%。
此时我们队列满的条件为(rear+1)%maxSize==front
判断队列空的条件仍为rear==front
计算队列长度的公式为(rear-0)+(maxSize-front)
此时我们要清楚:
front:指向队列的第一个元素,即arr[front]为队列的第一个元素,front的初始值=0
raer:rear指向队列的最后一个元素的后一个位置(空一个位置),rear的初始值=0
代码实现
class CircleArrayQueue { private int maxSize;//数组最大容量 private int front;//指向队列的第一个元素 private int rear;//指向队列最后一个元素的后一个位置 private int[] arr; // 创建数组 public CircleArrayQueue(int arrMaxSize) { maxSize = arrMaxSize; arr = new int[maxSize]; front =0;// 头数据的前一个位置 rear = 0; } // 判空 public boolean isEmpty() { return rear==front; } // 判满 public boolean isFull() { return (rear+1)%maxSize==front; } // 添加操作(添加一个数据) public void addQueue(int n) { if (isFull()) { System.out.println("队列满,不能加入数据!"); return; } arr[rear] = n; rear=(rear+1)%maxSize;//考虑取模 } // 出队列操作 public int getQueue() { if (isEmpty()) { throw new RuntimeException("队列空,不能取数据"); } int value = arr[front]; front = (front+1)%maxSize; return value; } // 得到头数据 public int headQueue() { if (isEmpty()) { throw new RuntimeException("队列空,没有头数据"); } return arr[front]; } // 显示队列 public void showQueue() { if (isEmpty()) { System.out.println("队列空,没有数据!"); return; } //遍历从front开始,遍历元素个数为rear-front+maxSize,%是因为i时下标; for (int i = front; i < front+size(); i++) { System.out.printf("arr[%d]=%d\n",i%maxSize,arr[i%maxSize]); } } private int size() { //个数 (rear-0)+(maxSize-front) return (rear-front+maxSize)%maxSize; } }