zoukankan      html  css  js  c++  java
  • 数据结构与算法—稀疏数组和队列

    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	",data);
    			}
    			System.out.println();
    		}
    		
    		int[][] array = getSparseArray(chessArr);
    		System.out.println("-------");
    		for(int i = 0 ; i< array.length;i++){
    			System.out.printf("%d	%d	%d	
    ",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	",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会随着队列的输入而改变
    • 当我们将数据输入队列时称为 addQueueaddQueue 的处理有两个步骤:思路分析

    (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
    ",i,arr[i]);
    		}
    	}
    }
    

     

    2.2 数组模拟环形队列

    之前实现的队列存在一个明显的问题,就是数组使用一次就不能再用了,出队列数据的位置始终空在那,没有达到一个复用的效果,因此我们要对这个队列进行一次优化,将此队列变成一个环形队列

    思路

    1. front 变量的含义做一个调整:front就指向队列的第一个元素,也就是 arr[front] 就代表队列的第一个元素,
      front初始值 = 0

    2. rear 的变量含义做一个调整:rear指向最后一个元素的后一个位置,因为希望空出一个空间作为约定,rear的初始值 = 0

    3. 当队列满时,条件是 (rear + 1) % maxSize == front 【满】

    4. 当队列为空的条件,rear == front 空

    5. 当我们这样分析,队列中有效的数据的个数 (rear + maxSize - front) % maxSize

    6. 我们就可以在原来的队列上修改得到 一个环形队列

     

    代码实现

    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
    ",res);
    				} catch (Exception e) {
    					System.out.println(e.getMessage());
    				}
    				break;
    			case 'h'://查看队列头的数据
    				try {
    					int res = queue.headQueue();
    					System.out.printf("队列头的数据是%d
    ",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
    ",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];
    	}
    	
    	
    }
    
  • 相关阅读:
    JS对象—对象总结(创建、属性、方法)
    总结30个css选择器
    null、undefined、typeof、instanceof
    Hybrid App 原理解析
    promise与async-await
    你不知道的javascript
    Function.prototype.toString 的使用技巧
    Javascript中的valueOf与toString
    HTML5 Page Visibility
    深入理解css3中 nth-child 和 nth-of-type 的区别
  • 原文地址:https://www.cnblogs.com/dwlovelife/p/11191444.html
Copyright © 2011-2022 走看看