數據結構與算法入門——排序算法之八大常用排序方法

冒泡排序

   //定義一個數組
        int[] arr = new int[]{8,5,7,6,1,3,9,4};
        //共比較多少輪
        for (int i = 0; i < arr.length-1; i++) {
            //一輪比較多少次
            for (int j = 0; j < arr.length-1-i; j++) {
                //如果前面的大於後面的,那麼前後交換
                if (arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

快速排序

 /**
     *
     * @param arr:傳入的參數數組
     * @param start:排序區間開始的下標
     * @param end:排序區間結束的下標
     */
    public static void quickSort(int[] arr,int start,int end){
        //如果開始下標沒有與結束下標重合,則一直循環
        if (start < end){
            //將當前排序區間的第一個數作爲比較的標準數
            int  stard = arr[start];
            //記錄排序需要的下標
            int low = start;
            int high = end;
            //如果開始座標小於結束座標,則開始循環
            while (low<high){
                //如果開始座標小於結束座標並且右邊的數大於左邊的標準數
                while (low<high&&stard<=arr[high]){
                    //結尾座標向前挪一位
                    high--;
                }
                //右邊結束座標的數替換掉左邊開始座標的數
                arr[low] = arr[high];
                //如果開始座標小於結束座標並且左邊的數小於標準數
                while (low<high&&arr[low]<=stard){
                    //左邊數的下標向前挪一位
                    low++;
                }
                //左邊開始座標的數替換掉右邊結束座標的數
                arr[high] = arr[low];
            }
            //當循環結束,即兩座標重疊時,將比較的標準數賦給當前座標的值
            arr[low] = stard;
            //重新開始比較標準數左邊的區間
            quickSort(arr,start,low);
            //重新開始比較標準數右邊的區間
            quickSort(arr,low+1,end);
        }
    }

插入排序

public static void insertSort(int[] arr){
        int temp;
        int j = 0;
        //從第二個遍歷整個數組
        for (int i = 1; i < arr.length; i++) {
            //如果當前數比前一個數小
            if (arr[i]<arr[i-1]){
                //把當前數存起來
                temp = arr[i];
                //遍歷當前數之前的所有的數
                for (j = i-1; j >=0&&temp<arr[j] ; j--) {
                    //如果遍歷到的數大於temp,則向後挪一位
                    arr[j+1] = arr[j];
                }
                //當前的數小於等於temp,則把temp賦值給他後一位數
                arr[j+1] = temp;
            }
        }
    }

希爾排序

public static void shellSort(int[] arr){
        //遍歷所有的步長
        for (int d = arr.length/2; d >0 ; d/=2) {
            //遍歷每一組中的第一個元素,與同一組的元素進行比較
            for (int i = d; i < arr.length; i++) {
                //遍歷本組中的所有元素
                for (int j = i-d; j >=0 ; j-=d) {
                    if (arr[j]>arr[j+d]){
                        int temp = arr[j];
                        arr[j] = arr[j+d];
                        arr[j+d] = temp;
                    }
                }
            }
        }
    }

選擇排序

 public static void chooseSort(int[] arr){
        //遍歷所有的數
        for (int i = 0; i <arr.length ; i++) {
            int minIndex = i;
            //把當前的數與之後所有的數全都比較一遍。並記錄下最小的數的下標
            for (int j = i+1; j <arr.length ; j++) {
                if (arr[j]<arr[minIndex]){
                    minIndex = j;
                }
            }
            //將最小的數與當前遍歷的數交換
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
        }
    }

歸併排序

 public static void MergeSort(int[] arr,int start,int end){
        //取出中間下標
        int middel = (start+end)/2;
        //只要開始下標小於結束下標,就會一直遞歸
        if (start<end){
            //處理左邊的數組
            MergeSort(arr,0,middel);
            //處理右邊的數組
            MergeSort(arr,middel+1,end);
            //歸併排序
            merge(arr,0,middel,end);
        }
    }

    public static void merge(int[] arr,int low,int middel,int high){
        //用於儲存歸併後的臨時數組
        int[] temp = new int[high-low+1];
        //記錄第一個數組中需要遍歷的下標
        int i = low;
        //記錄第二個數組中需要遍歷的下標
        int j = middel+1;
        //用於記錄在臨時數組中存放的下標
        int index = 0;
        //遍歷兩個數組中取出較小的數字,存放到新數組中
        while (i<=middel&&j<=high){
            //第一個數組的數字更小
            if (arr[i]<=arr[j]){
                temp[index] = arr[i];
                //下標後移一位
                i++;
                //第二個數組的數字更小
            }else {
                temp[index] = arr[j];
                j++;
            }
            index++;
        }
        //處理多餘的數據
        while (j<=high){
            temp[index]=arr[j];
            j++;
            index++;
        }
        while (i<=middel){
            temp[index]=arr[i];
            i++;
            index++;
        }
        //把臨時數組中的數據重新存入原數組
        for (int k = 0; k < temp.length; k++) {
            arr[k+low] = temp[k];
        }
    }

基數排序

/**
 * 採用數組形式
 */
  public static void radixSort(int[] arr){
        //定義一個最小值變量。Integer.MIN_VALUE:整形數中的最小值:-2147483648
        int max = Integer.MIN_VALUE;
        //遍歷找出數組中最大值
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]>max){
                max = arr[i];
            }
        }
        //計算最大數組是幾位數
        int maxLength = (max+"").length();
        //定義一個臨時存儲數據的二維數組
        int[][] temp = new int[10][arr.length];
        //用於記錄temp相對數組中數據的數量
        int[] count = new int[10];
        //根據最大長度決定比較次數,即最大數是幾位數,則比較幾次
        for (int i = 0,n=1; i < maxLength; i++,n*=10) {
            //把每一個數字分別計算餘數,按餘數分組
            for (int j = 0; j < arr.length; j++) {
                //計算餘數
                int ys = arr[j]/n%10;
                //把當前遍歷的數據放入指定的數組中
                temp[ys][count[ys]] = arr[j];
                //當前數組數據數量+1
                count[ys]++;
            }
            //記錄取的元素需要放的位置
            int index = 0;
            //再把分完組的數據重新放回原數組中
            for (int k = 0; k <count.length ; k++) {
                //判斷當前分組是否爲0
                if (count[k]!=0)
                    //若不爲0,則遍歷取出當前分組的數據
                    for (int l = 0; l < count[k]; l++) {
                        //原數組從0開始,臨時數組從有數據的分組開始
                        arr[index] = temp[k][l];
                        //原數組下標+1
                        index++;
                    }
                //取完後把count數組清空以便記錄下一次便利分組
                count[k] = 0;
            }
        }

    }

/**
 * 採用隊列形式
 */
  public static void radixSort_for_queue(int[] arr){
        //定義一個最小值變量。Integer.MIN_VALUE:整形數中的最小值:-2147483648
        int max = Integer.MIN_VALUE;
        //遍歷找出數組中最大值
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]>max){
                max = arr[i];
            }
        }
        //計算最大數組是幾位數
        int maxLength = (max+"").length();
        //定義一個臨時存儲數據的隊列的數組(即創建10個隊列)
        QueueUtil[] temp = new QueueUtil[10];
        //爲每一組隊列賦值
        for (int i = 0; i < temp.length; i++) {
            temp[i] = new QueueUtil();
        }
        //根據最大長度決定比較次數,即最大數是幾位數,則比較幾次
        for (int i = 0,n=1; i < maxLength; i++,n*=10) {
            //把每一個數字分別計算餘數,按餘數分組
            for (int j = 0; j < arr.length; j++) {
                //計算餘數
                int ys = arr[j]/n%10;
                //把當前遍歷的數據放入指定的隊列中
                temp[ys].add(arr[j]);
            }
            //記錄取的元素需要放的位置
            int index = 0;
            //再把分完組的數據重新放回原數組中
            for (int k = 0; k <temp.length ; k++) {
                //判斷當前分組是否爲0
                while (!temp[k].isEmpty()){
                    //原數組從0開始,隊列從有數據的開始
                    arr[index] = temp[k].pop();
                    //原數組下標+1
                    index++;
                }
            }
        }
    }

堆排序

  • 堆排序涉及到二叉樹的知識,如果沒接觸過二叉樹的道友可先看這篇文章
     https://blog.csdn.net/qq_40181435/article/details/104733767
    
/**
 * 升序用大頂堆
 * 降序用小頂堆
 * */
 
  public static void heapSort(int[] arr){
        int start = (arr.length-1)/2;
        //調整爲大頂堆
        for (int i = start; i >=0; i--) {
            maxHeap(arr,arr.length,i);
        }
        //先把數組中前後交換,然後再把前面的處理成大頂堆
        for (int i = arr.length-1; i >0 ; i--) {
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            maxHeap(arr,i,0);
        }

    }

    /**
     * @param arr:傳遞的數組
     * @param size:排序的範圍
     * @param index:初始父節點
     */
    public static void maxHeap(int[] arr,int size,int index){
        //左子結點
        int leftNode = 2*index+1;
        //右子結點
        int rightNode = 2*index+2;
        //父節點
        int max = index;
        //與兩個子結點對比,找出最大節點
        if (leftNode<size&&arr[leftNode]>arr[max]){
            //如果左子結點大於父節點,那麼二者交換
            max = leftNode;
        }
        if (rightNode<size&&arr[rightNode]>arr[max]){
            //如果右子結點大於父節點,那麼二者交換
            max = rightNode;
        }
        //交換位置
        if (max != index){
            int temp = arr[index];
            arr[index] = arr[max];
            arr[max] = temp;
            maxHeap(arr,size,max);
        }
        //交換位置後,可能破壞之前排好的堆,所以需要重新調整之前排好的堆

    }
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章