Java實現【快速排序】【歸併排序】【桶排序/基數排序】

一、快速排序

快速排序算法通過多次比較和交換來實現排序,其排序流程如下:
1.首先設定一個分界值,通過該分界值將數組分成左右兩部分。
2.將大於或等於分界值的數據集中到數組右邊,小於分界值的數據集中到數組的左邊。此時,左邊部分中各元素都小於或等於分界值,而右邊部分中各元素都大於或等於分界值。
3.然後,左邊和右邊的數據可以獨立排序。對於左側的數組數據,又可以取一個分界值,將該部分數據分成左右兩部分,同樣在左邊放置較小值,右邊放置較大值。右側的數組數據也可以做類似處理。
4.重複上述過程,可以看出,這是一個遞歸定義。通過遞歸將左側部分排好序後,再遞歸排好右側部分的順序。當左、右兩個部分各數據排序完成後,整個數組的排序也就完成了。

public class QuickSort {
    public static void main(String[] args) {

//        int[] arrays = {101, 34, 119, 1};
//        int[] result = insertSort(arrays);
//        System.out.println(Arrays.toString(result));

        //速度測試  8049
        long begin = System.currentTimeMillis();

        int[] array = new int[8];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] results = quickSort(array,0,array.length-1);

        long end = System.currentTimeMillis();
        System.out.println("用時:"+(end - begin));
        System.out.println(Arrays.toString(results));
    }

    public static int[] quickSort(int[]arr,int left,int right){
//        System.out.println(Arrays.toString(arr));
        //左下標
        int lIndex = left;
        //右下標
        int rIndex = right;
        //pivot中軸值
        int pivot = arr[(left + right) / 2];
        //臨時變量
        int temp = 0;
        //while循環的目的是讓比pivot值小放到左邊,比pivot大的放到右邊
        while(lIndex < rIndex){
            //pivot的左邊一直找,找到>=pivot的值時退出
            while (arr[lIndex] < pivot){
                lIndex += 1;
            }
            while (arr[rIndex] > pivot){
                rIndex -= 1;
            }
//            System.out.println(Arrays.toString(arr));
            //若lIndex>=rIndex說明左邊已經全部都是小於pivot的值,右邊已全部都是大於pivot的值
            if(lIndex >= rIndex){
                break;
            }
            //進行值的交換
            temp = arr[lIndex];
            arr[lIndex] = arr[rIndex];
            arr[rIndex] = temp;
            //交換完成後若arr[lIndex] == pivot 相同,說明pivot左邊已完成排序,右邊的指針前移
            if(arr[lIndex] == pivot){
                rIndex -= 1;
            }
            //交換完成後若arr[rIndex] == pivot 相同,說明pivot右邊已完成排序,左邊的指針後移
            else if(arr[rIndex] == pivot){
                lIndex += 1;
            }
        }
        //如果lIndex == rIndex ,需將左指針後移 ,右指針前移 避免出現棧溢出
        if(lIndex == rIndex){
            lIndex++;
            rIndex--;
        }
        //若右指針比初始的做指針大,說明左邊沒有進行排序
        if(left < rIndex){
            quickSort(arr,left,rIndex);
        }
        if(right > lIndex){
            quickSort(arr,lIndex,right);
        }
        return arr;
    }
}

二、歸併排序

歸併操作的工作原理如下:
1.申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
2.設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
3.比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
4.重複步驟3直到某一指針超出序列尾
5.將另一序列剩下的所有元素直接複製到合併序列尾

public class MergeSort {

    public static void main(String[] args) {

//        int[] arrays = {101, 34, 119, 1};
//        int[] temp = new int[arrays.length];
//        mergeSort(arrays, 0, arrays.length - 1, temp);
//        System.out.println(Arrays.toString(arrays));

        //速度測試  8049
        long begin = System.currentTimeMillis();

        int[] array = new int[80000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] temp = new int[array.length];
        mergeSort(array, 0, array.length - 1, temp);

        long end = System.currentTimeMillis();
        System.out.println("用時:" + (end - begin));
//        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] arrays, int left, int right, int[] temp) {
        if (left < right) {
            int pivot = (left + right) / 2;
            mergeSort(arrays, left, pivot, temp);
            mergeSort(arrays, pivot + 1, right, temp);
            merge(arrays, left, pivot, right, temp);

        }
    }

    public static void merge(int[] arrays, int left, int pivot, int right, int[] temp) {
        //初始化左邊有序序列的初始索引
        int leftIndex = left;
        //初始化右邊有序序列的初始索引
        int rightIndex = pivot + 1;
        //指向temp數組的當前索引
        int tempIndex = 0;

        //一.先把左右兩邊(有序)的數組按照規則填充到temp數組中
        //直到左右兩邊的有序序列,有一邊處理完成爲止
        while (leftIndex <= pivot && rightIndex <= right) {
            if (arrays[leftIndex] <= arrays[rightIndex]) {
                temp[tempIndex] = arrays[leftIndex];
                leftIndex++;
                tempIndex++;
            } else {
                temp[tempIndex] = arrays[rightIndex];
                rightIndex++;
                tempIndex++;
            }
        }

        while (leftIndex <= pivot) {
            temp[tempIndex] = arrays[leftIndex];
            tempIndex++;
            leftIndex++;
        }
        while (rightIndex <= right) {
            temp[tempIndex] = arrays[rightIndex];
            tempIndex++;
            rightIndex++;
        }

        tempIndex = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            arrays[tempLeft] = temp[tempIndex];
            tempIndex++;
            tempLeft++;
        }
    }
}

三、桶排序/基數排序

基本思想:先排好個位,再排十位,百位,千位…

1.創建10個的桶,下標從0到9。
2.遍歷原數據,獲取元素的個位,將其放入匹配下標的桶中。
3.全部放入之後再取出替換原數據,再將排序過一次的原數據遍歷,獲取元素的十位,將其放入匹配下標的桶中,依次百位,千位…
4.最後一次放到桶中,再按照桶的下標從0-9將其中的數據取出,就獲得到了有序數列。

public class RadixSort {
    public static void main(String[] args) {
/*
        int[] arrays = {101, 34, 119, 1};
        int[] result = radixSort(arrays);
        System.out.println(Arrays.toString(result));
*/


        //速度測試  91
        long begin = System.currentTimeMillis();

        int[] array = new int[8000000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 8000000);
        }
        int[] results = radixSort(array);

        long end = System.currentTimeMillis();
        System.out.println("用時:"+(end - begin));
//        System.out.println(Arrays.toString(results));
    }


    public static int[] radixSort(int[] arrays) {
        //數組中最大數
        int max = arrays[0];
        for (int i = 1; i < arrays.length; i++) {
            if (arrays[i] > max) {
                max = arrays[i];
            }
        }
        //最大數是幾位數
        int maxLength = (max + "").length();

        // 定義10個桶,每個桶是一個數組
        /*說明
            1. 二維數組包含10個一維數組
		    2. 爲了防止在放入數的時候,數據溢出,則每個一維數組(桶),大小定爲arrays.length
		    3. 明確,基數排序是使用空間換時間的經典算法
         */
        int[][] bucket = new int[10][arrays.length];

        //定義一個數組記錄每個桶實際存放的數據個數
        int[] bucketCounts = new int[10];
        //取出數據用
        int index = 0;
        //使用循環進行排序
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            //針對每個元素對應的位數進行處理,第一次處理個位數,第二次處理十位,以此類推
            for (int j = 0; j < arrays.length; j++) {
                //取出每個元素對應位數的值
                int digitOfElement = arrays[j] / n % 10;
                //將其放入對應的桶中
                bucket[digitOfElement][bucketCounts[digitOfElement]] = arrays[j];
                //將指針向前移動一下
                bucketCounts[digitOfElement]++;
            }
            //按照這個桶的順序(一維數組的下標依次取出數據,放入到原來的數組中)
            index = 0;
            //遍歷每一個桶中的數據
            for (int k = 0; k < bucketCounts.length; k++) {
                //只有桶中有數據時才放入原數組
                if(bucketCounts[k]!=0){
                    //循環第k個桶
                    for (int l = 0;l < bucketCounts[k];l++){
                        //取出元素放入arrays
                        arrays[index++] = bucket[k][l];
                    }
                }
                //第i+1輪處理後將桶的指針回到初始位置
                bucketCounts[k] = 0;
            }
        }

        return arrays;
    }
}

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