數據結構與算法—稀疏數組和隊列

稀疏數組和隊列

1.稀疏數組

所謂稀疏數組就是當數組中大部分的內容值都未被使用(或都爲零),在數組中僅有少部分的空間使用。所以形成內存空間的浪費,爲了節省內存空間,而且不影響數組中原有的內容值,咱們可使用稀疏數組去壓縮數據。OK,若是你不明白,那咱們來看一個例子。小程序

 

在一個五子棋中,有存盤和續上盤的功能數組

分析問題:由於該二維數組的不少默認值是 0,所以記錄了不少沒有意義的數據 > 稀疏數組數據結構

 

1.1 解決方法

思路oop

  • 記錄數組一共有幾行幾列,有多少個不一樣的值測試

  • 把具備不一樣值的元素的行列及值記錄在一個小規模的數組中,從而縮小程序的範圍優化

     

應用實例this

  • 使用稀疏數組,來保留相似前面的二維數組(棋盤、地圖等等)
  • 把稀疏數組存盤,而且能夠重新恢復爲原來的二維數組
  • 總體思路

 

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會隨着隊列的輸入而改變
  • 當咱們將數據輸入隊列時稱爲 addQueueaddQueue的處理有兩個步驟:思路分析

(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]);
        }
    }
}

 

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\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];
    }
    
    
}
相關文章
相關標籤/搜索