客服測試客服

public class SortTest {
    public static int countGB = 0;

    public static void main(String[] args) {
        int[] array = {1, 12, 8, 9, 6, 8, 4, 7, 2, 3, 5, 4, 6, 0};
        long startTime = System.currentTimeMillis();    //獲取開始時間

//        int[] array1 = MP(array);//冒泡排序
//        int[] array1 = XZ(array);//選擇排序
//        int[] array1 = CR(array);//插入排序
//        int[] array1 = XE(array);//希爾排序
//        int[] array1 = GB(array);//歸併排序
//        System.out.println(countGB);//歸併排序循環次數 54 最佳情況:T(n) = O(n)  最差情況:T(n) = O(nlogn)  平均情況:T(n) = O(nlogn)
//        KS(array, 0, array.length - 1);//快速排序
//        System.out.println(countGB);//快速排序循環次數 46 最佳情況:T(n) = O(nlogn)   最差情況:T(n) = O(n2)   平均情況:T(n) = O(nlogn) 
//        for (int i = 0; i < array.length; i++) {
//            System.out.print(array[i] + " ");
//        }
//        int[] array1 = D(array);//堆排序
//        System.out.println(countGB);//堆排序循環次數 49 最佳情況:T(n) = O(nlogn) 最差情況:T(n) = O(nlogn) 平均情況:T(n) = O(nlogn)
//        int[] array1 = JS(array);//計數排序

//        ArrayList<Integer> arrayList = new ArrayList<Integer>();
//        for (int i = 0; i < array.length; i++) {
//            arrayList.add(array[i]);
//        }
//        ArrayList array1 = T(arrayList, 10);//桶排序 556次,速度太慢了,循環次數太多了 最佳情況:T(n) = O(n+k)   最差情況:T(n) = O(n+k)   平均情況:T(n) = O(n2) k是桶的個數,選bucketSize也很重要,對於不同數組選取不一樣的bucketSize區別很大
//        for (int i = 0; i < array1.size(); i++) {
//            System.out.print(array1.get(i) + " ");
//        }
//        System.out.println();
//        System.out.println(countGB);

//        int[] array1=basket(array);//桶排序
//        int[] array1 = radix(array);//基數排序
        int[] array1 = RadixSort(array);//基數排序

        long endTime = System.currentTimeMillis();    //獲取結束時間
        System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + " ");
        }
    }

    /**
     * 冒泡排序
     *
     * @param arr
     * @return
     */
    public static int[] MP(int[] arr) {
        if (arr.length <= 1) {
            return arr;
        }
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            int flag = 0;
            for (int j = 0; j < arr.length - i - 1; j++) {
                count++;
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                    flag++;
                }
            }
            if (flag == 0) {
                break;
            }
        }
        System.out.println(count);//91 最佳情況:T(n) = O(n)   最差情況:T(n) = O(n2)   平均情況:T(n) = O(n2)
        return arr;
    }

    /**
     * 選擇排序
     *
     * @param arr
     * @return
     */
    public static int[] XZ(int[] arr) {
        if (arr.length <= 1) {
            return arr;
        }
        long startTime = System.currentTimeMillis();    //獲取開始時間
//        /**
//         * TODO:這裏使用的方法需要一直替換數組內的值,會破壞原來的數組,但是沒關係
//         */
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                count++;
                if (arr[i] > arr[j]) {
                    int change = arr[j];
                    arr[j] = arr[i];
                    arr[i] = change;
                }
            }
        }
//        /**
//         * TODO:這裏使用的方法除了將最小值和未排序列的第一個值作交換外,不破壞未排序序列的順序
//         */

//        for(int i=0;i<arr.length;i++){
//            int minIndex=i;
//            for(int j=i;j<arr.length;j++){
//                count++;
//                if(arr[minIndex]>arr[j]){
//                    minIndex=j;
//                }
//            }
//            int temp=arr[minIndex];
//            arr[minIndex]=arr[i];
//            arr[i]=temp;
//        }
        long endTime = System.currentTimeMillis();    //獲取結束時間
        System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
        System.out.println(count);//1、91 2、105 最佳情況:T(n) = O(n2)  最差情況:T(n) = O(n2)  平均情況:T(n) = O(n2)
        return arr;
    }

    /**
     * 插入排序
     *
     * @param arr
     * @return
     */
    public static int[] CR(int[] arr) {
        long startTime = System.currentTimeMillis();    //獲取開始時間
        if (arr.length <= 1) {
            return arr;
        }
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i - 1; j >= 0 && arr[j + 1] < arr[j]; j--) {//往後移動,只要i+1的這個值比前面已經排好序的小,就把前面的值往後移動一個位置(原理:因爲前面已經排好序了,只要找到第一個比自己小的那個位置放到那個後面就行了)
                count++;
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }

        long endTime = System.currentTimeMillis();    //獲取結束時間
        System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
        System.out.println(count);//61 最佳情況:T(n) = O(n)   最壞情況:T(n) = O(n2)   平均情況:T(n) = O(n2)
        return arr;
    }

    /**
     * 希爾排序
     * 插入排序升級版
     *
     * @param arr
     * @return
     */
    public static int[] XE(int[] arr) {
        long startTime = System.currentTimeMillis();    //獲取開始時間
        if (arr.length <= 1) {
            return arr;
        }
        int gap = arr.length / 2;
        int count = 0;
        while (gap > 0) {
            for (int i = gap; i < arr.length; i++) {
                for (int j = i - gap; j >= 0 && arr[j + gap] < arr[j]; j = j - gap) {
                    count++;
                    int temp = arr[j];
                    arr[j] = arr[j + gap];
                    arr[j + gap] = temp;
                }
            }
            for (int i = 0; i < arr.length; i++) {
                System.out.print(" " + arr[i]);
            }
            System.out.println();
            gap /= 2;

        }
        long endTime = System.currentTimeMillis();    //獲取結束時間
        System.out.println("程序運行時間:" + (endTime - startTime) + "ms");
        System.out.println(count);//19 最佳情況:T(n) = O(nlog2 n)  最壞情況:T(n) = O(nlog2 n)  平均情況:T(n) =O(nlog2n) 
        return arr;
    }

    /**
     * 歸併排序
     *
     * @param arr
     * @return
     */
    public static int[] GB(int[] arr) {
        if (arr.length <= 1) {
            return arr;
        }
        return merge(GB(Arrays.copyOfRange(arr, 0, arr.length / 2)), GB(Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
    }

    /**
     * 合併左右數組
     *
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
            countGB++;
            if (i >= left.length) {
                result[index] = right[j++];// <=> result[index]=right[j];j++;
            } else if (j >= right.length) {
                result[index] = left[i++];
            } else if (left[i] > right[j]) {
                result[index] = right[j++];
            } else {
                result[index] = left[i++];
            }
        }
        return result;
    }

    /**
     * 快速排序
     *
     * @param arr
     * @return
     */
    public static void KS(int[] arr, int left, int right) {
        if (arr.length <= 1) return;
        if (left > right) {
            return;
        }
        int i = left, j = right, key = arr[left];
        while (i < j) {
            while (i < j && arr[j] > key) {//從右往左找第一個比key值小的數,找到後退出循環,這樣保留j的值,這個arr[j]就是第一個小於key的值
                countGB++;
                j--;
            }
            while (i < j && arr[i] <= key) {//從左往右找第一個比key值大的數,找到後退出循環,保留i的值,用來替換從右邊找的第一個小於key的值,這樣兩個對調之後相當於以key爲中心,左邊爲小於key的值,右邊爲大於key的值
                countGB++;
                i++;
            }
            if (i < j) {//對調,對調後arr[i]爲小於key的值,arr[j]爲大於key的值
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        arr[left] = arr[i];//將key值與小於key的值對調,這樣key的左邊就是小於key的,右邊是小於key的
        arr[i] = key;//現在第i個爲key了,後面只需要對key的左右兩邊進行快排就可以了
//        System.out.println("i:"+i);
        KS(arr, left, i - 1);// 對key左邊的數快排
        KS(arr, i + 1, right);// 對key右邊的數快排
    }

    /**
     * 堆排序
     *
     * @param arr
     * @return
     */
    public static int[] D(int[] arr) {
        if (arr.length <= 1) return arr;
        for (int i = 0; i < arr.length; i++) {
            buildMaxD(arr, arr.length - i);//從最後一個開始,每次建堆把最後一個位置存放最大值達到排序的目的
            int temp = arr[0];
            arr[0] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = temp;
        }
        return arr;
    }

    /**
     * 建堆
     *
     * @param arr
     * @param currentRootNode 當前父節點位置(數組小標)
     * @param size            節點總數
     */
    public static void buildD(int[] arr, int currentRootNode, int size) {
//        System.out.print(currentRootNode + ":" + size);
        if (currentRootNode < size) {
            //左子樹和右字數的位置
            int leftChildNode = 2 * currentRootNode + 1;
            int rightChildNode = 2 * currentRootNode + 2;
            //假設節點是最大值節點的位置,max用來記錄最大值的位置
            int max = currentRootNode;
            if (leftChildNode < size) {
                if (arr[leftChildNode] > arr[max]) {//如果左節點大於當前記錄的值,將記錄的位置換成當前位置
                    max = leftChildNode;
                }
            }
            if (rightChildNode < size) {
                if (arr[rightChildNode] > arr[max]) {//如果右節點大於當前記錄的值,將記錄的位置換成當前位置
                    max = rightChildNode;
                }
            }
            if (max != currentRootNode) {//將當前父節點的位置上的值,與記錄的最大值位置的值進行對調,這樣當前父節點位置的值就大於子節點了
                int temp = arr[currentRootNode];
                arr[currentRootNode] = arr[max];
                arr[max] = temp;
            }
//            System.out.println(":" + max);
        }
    }

    /**
     * 構建最大堆
     *
     * @param arr
     * @param size
     */
    public static void buildMaxD(int[] arr, int size) {
        // 從數組的尾部開始,直到第一個元素(角標爲0)
        for (int i = size / 2 - 1; i >= 0; i--) {//這裏初始值爲啥是size/2-1呢,因爲要從第一個非葉子節點開始查起,最後一個葉子節點如果是左子樹,它的值爲2x+1,x爲父節點位置,size-1=2x+1 =>x=size/2 -1
            //最後一個葉子節點如果是右子樹,它的值爲2x+2,x爲父節點位置,size-1=2x+2 =>x=size/2 -3/2 所以取x=size/2-1臨界值,能夠保證第一個父節點不會漏掉,也能避免多餘的循環
            buildD(arr, i, size);
            countGB++;
        }
    }

    /**
     * 計數排序
     *
     * @param arr
     * @return
     */
    public static int[] JS(int[] arr) {
        if (arr.length <= 1) return arr;
        int bias, min = arr[0], max = arr[0];
        int count = 0;
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
            if (arr[i] < min) {
                min = arr[i];
            }
            count++;
        }
        bias = 0 - min;
        int[] bucket = new int[max - min + 1];
        Arrays.fill(bucket, 0);
        for (int i = 0; i < arr.length; i++) {
            bucket[arr[i] + bias]++;
            count++;
        }

//        int index=0,k=0;
//        while (index<arr.length){
//            if(bucket[k]!=0){
//                arr[index]=k-bias;
//                bucket[k]--;
//                index++;
//            }else {
//                k++;
//            }
//            count++;
//        }

        for (int i = 0, j = 0; i < bucket.length; i++) {
            while (bucket[i] > 0) {
                arr[j] = i - bias;
                j++;
                bucket[i]--;
                count++;
            }
        }
        System.out.println(count);//計數排序循環次數 1、53 2、41  T(n) = O(n+k)  最差情況:T(n) = O(n+k)  平均情況:T(n) = O(n+k)
        return arr;
    }

    /**
     * 桶排序
     * 計數排序的升級版
     * 桶排序是計數排序的變種,它利用了函數的映射關係,高效與否的關鍵就在於這個映射函數的確定。把計數排序中相鄰的m個”小桶”放到一個”大桶”中,在分完桶後,對每個桶進行排序(一般用快排),然後合併成最後的結果。
     *
     * @param arr
     * @param bucketSize 人爲設置一個BucketSize,作爲每個桶所能放置多少個不同數值(例如當BucketSize==5時,該桶可以存放{1,2,3,4,5}這幾種數字,但是容量不限,即可以存放100個3);
     * @return
     */
    public static ArrayList<Integer> T(ArrayList<Integer> arr, int bucketSize) {
        if (arr == null || arr.size() <= 1)
            return arr;
        int max = arr.get(0), min = arr.get(0);
        for (int i = 1; i < arr.size(); i++) {
            countGB++;
            if (max < arr.get(i)) {
                max = arr.get(i);
            }
            if (min > arr.get(i)) {
                min = arr.get(i);
            }
        }
        int bucketCount = (max - min) / bucketSize + 1;
        ArrayList<ArrayList> bucketArr = new ArrayList(bucketCount);
        ArrayList resultArr = new ArrayList();
        for (int i = 0; i < bucketCount; i++) {
            countGB++;
            bucketArr.add(new ArrayList<>());
        }
        for (int i = 0; i < arr.size(); i++) {
            countGB++;
            bucketArr.get((arr.get(i) - min) / bucketSize).add(arr.get(i));
        }
        for (int i = 0; i < bucketCount; i++) {
            if (bucketSize == 1) {
                for (int j = 0; j < bucketArr.get(i).size(); j++) {
                    countGB++;
                    resultArr.add(bucketArr.get(i).get(j));
                }
            } else {
                if (bucketCount == 1) {
                    bucketSize--;
                }
                ArrayList temp = T(bucketArr.get(i), bucketSize);
                for (int j = 0; j < temp.size(); j++) {
                    countGB++;
                    resultArr.add(temp.get(j));
                }
            }
        }
        return resultArr;
    }

    /**
     * 進階版桶排序,通過整數的位數來計算 來源於百度百科
     *
     * @param data
     * @return
     */
    public static int[] basket(int data[])//data爲待排序數組
    {
        if (data.length < 2) {
            return data;
        }
        int count = 0;
        int n = data.length;
        int bask[][] = new int[10][n];
        int index[] = new int[10];
        int max = Integer.toString(data[0]).length();
        for (int i = 0; i < n; i++) {
            count++;
            max = max > (Integer.toString(data[i]).length()) ? max : (Integer.toString(data[i]).length());
        }
        String str;
        for (int i = max - 1; i >= 0; i--) {
            for (int j = 0; j < n; j++) {
                str = "";
                if (Integer.toString(data[j]).length() < max) {
                    for (int k = 0; k < max - Integer.toString(data[j]).length(); k++) {
                        str += "0";
                        count++;
                    }
                } else {
                    count++;
                }
                str += Integer.toString(data[j]);
                bask[str.charAt(i) - '0'][index[str.charAt(i) - '0']++] = data[j];
            }
            int pos = 0;
            for (int j = 0; j < 10; j++) {
                for (int k = 0; k < index[j]; k++) {
                    count++;
                    data[pos++] = bask[j][k];
                }
            }
            for (int x = 0; x < 10; x++) {
                count++;
                index[x] = 0;
            }
        }
        System.out.println(count);//循環次數 90 ,當數組內的值最大最小值之差變大時循環次數會增加很多很多,當不同位數的值比較多時,循環次數增加,比如 1 10 100 1000
        return data;
    }

    /**
     * 基數排序
     * 最佳情況:T(n) = O(n * k)   最差情況:T(n) = O(n * k)   平均情況:T(n) = O(n * k) 來源於百度百科
     *
     * @param number
     * @return
     */
    public static int[] radix(int[] number) {
        if (number.length < 2) {
            return number;
        }
        int count = 0;
        int d = 0;//d表示最大的數有多少位
        for (int i = 0; i < number.length; i++) {
            count++;
            d = d > Integer.toString(number[i]).length() ? d : Integer.toString(number[i]).length();
        }

        int n = 1;
        int m = 1; //控制鍵值排序依據在哪一位
        int[][] temp = new int[10][number.length]; //數組的第一維表示可能的餘數0-9  第二維的數組下標表示這個餘數重複的個數
        int[] order = new int[10]; //數組orderp[i]用來表示該位是i的數的個數
        while (m <= d) {
            for (int i = 0; i < number.length; i++) {
                count++;
                int lsd = ((number[i] / n) % 10);//除以位數值(1 100 1000)再對10取餘得到第m位的個位數的值
                temp[lsd][order[lsd]] = number[i];//表示當前餘數LSD第 order[lsd]重複的那個數是number[i]
                order[lsd]++;//當前位數的個位數的值的個數 (比如129 當m=2時,當前位數爲2,當前位數的個位數是(129/10)%10等於2 如果還有一個321,那麼order[2]++的值就是兩個了
            }
            for (int i = 0, k = 0; i < 10; i++) {
                if (order[i] != 0) {
                    for (int j = 0; j < order[i]; j++) {
                        count++;
                        number[k] = temp[i][j];
                        k++;
                    }
                } else {
                    count++;
                }
                order[i] = 0;
            }
            n *= 10;
            m++;
        }
        System.out.println(count);//循環次數78次
        return number;
    }

    /**
     * 基數排序
     *
     * @param array
     * @return
     */
    public static int[] RadixSort(int[] array) {
        if (array == null || array.length < 2)
            return array;
        int count = 0;
        // 1.先算出最大數的位數;
        int maxDigit = 0;
        for (int i = 0; i < array.length; i++) {
            count++;
            maxDigit = maxDigit > Integer.toString(array[i]).length() ? maxDigit : Integer.toString(array[i]).length();
        }
        int mod = 10, div = 1;
        ArrayList<ArrayList<Integer>> bucketList = new ArrayList<ArrayList<Integer>>();
        for (int i = 0; i < 10; i++) {
            count++;
            bucketList.add(new ArrayList<Integer>());
        }
        for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
            for (int j = 0; j < array.length; j++) {
                count++;
                int num = (array[j] % mod) / div;//獲取第maxDigit位的個位數
                bucketList.get(num).add(array[j]);
            }
            int index = 0;
            for (int j = 0; j < bucketList.size(); j++) {
                for (int k = 0; k < bucketList.get(j).size(); k++) {
                    count++;
                    array[index++] = bucketList.get(j).get(k);
                }
                bucketList.get(j).clear();
            }
        }
        System.out.println(count);//循環次數80
        return array;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章