八大排序算法Java實現

JDK7的Collections.sort()的算法是TimSort, 適應性的歸併排序, 比較晦澀難懂, 這裏沒有實現node

複製代碼
public class mySort {
    
    // 冒泡排序
    public static void myBubbleSort(int[] array) {
        int lastExchange = array.length - 1;    //記錄最後交換位置, 避免重複比較
        for (int i = lastExchange - 1; i >= 0; --i) {
            for (int j = 0; j <= i; ++j) {
                if (array[j] > array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    lastExchange = j;   //特性:最後交互位置後的元素已經有序
                }
            }
        }
    }
    
    
    // 插入排序
    public static void myInsertSort(int[] array) {
        for (int i = 1; i <= array.length - 1; ++i) {
            int temp = array[i];
            int j = 0; // 給值移位並尋找插入點
            for (j = i - 1; j >= 0 && array[j] > temp; --j) {
                array[j + 1] = array[j];
            }
            array[j + 1] = temp;
        }
    }

    
    // 選擇排序
    public static void mySelectSort(int[] array) {
        for (int i = 0; i < array.length - 1; ++i) {
            int minIndex = i;
            // 每次選出一極值
            for (int j = i + 1; j <= array.length - 1; ++j) {
                if (array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            // 極值歸位
            if (minIndex != i) {
                int temp = array[minIndex];
                array[minIndex] = array[i];
                array[i] = temp;
            }
        }
    }

    
    // 希爾排序
    public static void myShellSort(int[] array) {
        int gap = 5;
        while (gap != 0) {
            //沒必要刻意分組, 組1->組2->組1->組2...輪流處理
            for (int j = gap; j <= array.length - 1; ++j) {
                int temp = array[j];
                int k = 0;
                for (k = j - gap; k >= 0 && array[k] > temp; k -= gap) {
                    array[k + gap] = array[k];
                }
                array[k + gap] = temp;
            }
            gap /= 2;   //從新分組
        }
    }

    
    // 快速排序
    public static void myQuickSort(int[] array) {
        myQuickSortCore(array, 0, array.length - 1);
    }
    private static void myQuickSortCore(int[] array, int left, int right) {
        if (left >= right) {   //遞歸出口
            return;
        }
        int mLeft = left;
        int mRight = right;
        
        int base = array[mLeft];  //第一個元素做爲基準, left空位可佔
        while(mLeft != mRight) {
            while (mRight > mLeft && array[mRight] >= base) {
                --mRight;
            }
            array[mLeft] = array[mRight];  //right可覆蓋
            while (mRight > mLeft && array[mLeft] <= base) {
                ++mLeft;
            }
            array[mRight] = array[mLeft];
        }
        array[mRight] = base; //基準元素歸位, l=r
        
        myQuickSortCore(array, left, mLeft - 1);  //遞歸基準以左
        myQuickSortCore(array, mRight + 1 , right);  //遞歸基準以右
    }
    
    
    // 歸併排序
    public static void myMergeSort(int[] array) {
        // 每一個分組中有兩個來自上層迭代的有序組, gap爲有序組長度, 2 * gap爲分組長度
        for (int gap = 1; gap < array.length; gap *= 2) {
            int i = 0; // array下標
            // 分組並內部排序
            while (i + 2 * gap - 1 < array.length) {
                mergePiece(array, i, i + gap - 1, i + 2 * gap - 1);
                i += 2 * gap;
            }
            // 分組剩餘部分排序, 只有超過一個gap纔有內部排序的意義
            if (i + gap - 1 < array.length) {
                mergePiece(array, i, i + gap - 1, array.length - 1);
            }
        }
    }
    // 將array中有序的兩段piecewise1 和 piecewise2 合併成總體有序
    public static void mergePiece(int[] array, int head, int mid, int tail) {
        int i = head; // piecewise1下標 [head, mid]
        int j = mid + 1; // piecewise2下標 [mid + 1, tail]
        // 臨時數組, 保存結果
        int[] arrayTemp = new int[tail - head + 1]; // combine
        int k = 0; // combine下標
        while (i <= mid && j <= tail) {
            if (array[i] <= array[j]) {
                arrayTemp[k] = array[i];
                ++i;
                ++k;
            } else {
                arrayTemp[k] = array[j];
                ++j;
                ++k;
            }
        }
        // 複製多餘部分 piecewise1
        while (i <= mid) {
            arrayTemp[k] = array[i];
            ++i;
            ++k;
        }
        // 複製多餘部分 piecewise2
        while (j <= tail) {
            arrayTemp[k] = array[j];
            ++j;
            ++k;
        }
        // 結果複製到原始數組
        k = 0;
        i = head; // 重置下標, i piecewise1 + piecewise2
        while (i <= tail) {
            array[i] = arrayTemp[k];
            ++i;
            ++k;
        }
    }

    
    // 堆排序
    public static void myHeapSort(int[] array) {
        // 調整堆->大頂堆
        for (int i = array.length / 2 - 1; i >= 0; --i) { // 從最後非葉子節點開始
            adjustHeap(array, i, array.length);
        }
        // 調整堆->交換堆頂/末位元素
        for (int j = array.length - 1; j > 0; --j) {
            int temp = array[0];
            array[0] = array[j];
            array[j] = temp;
            adjustHeap(array, 0, j); // 只需調整堆頂父節點
        }
    }
    // 調整爲大頂堆分佈, node爲父節點下標, adjustLen爲涉及調整的長度(爲排序使用)
    private static void adjustHeap(int[] array, int node, int adjustLen) {
        int temp = array[node]; // 拿出node造成可佔空位
        for (int i = node * 2 + 1; i < adjustLen; i = node * 2 + 1) {
            if (i + 1 < adjustLen && array[i] < array[i + 1]) {
                ++i; // 獲得最大子節點
            }
            if (array[i] > temp) {
                array[node] = array[i];
                node = i; // 爲下一層迭代更新父節點node, 最後爲葉子
            } else {
                break;
            }
        }
        array[node] = temp;
    }
    
    
    // 基數排序
    public static void myRadixSort(int[] array) {
        int d = maxBit(array);
        int dec = 1; //進制迭代
        final int R = 10;  //桶個數
        int[] tempArray = new int[array.length];  //臨時數組, 代替桶存儲數組, 代價是需記錄下標/數量來分割桶
        int[] bucketCapacity = new int[R];  //桶計數 
        for (int i = 1; i <= d; ++i) {
            for (int j = 0; j < R; ++j) {
                bucketCapacity[j] = 0;   //清空桶容量
            }
            //計數1
            for (int j = 0; j < array.length; ++j) {
                int k = array[j] / dec % R;  
                ++bucketCapacity[k];
            }
            //計數2 變累計, 爲分割
            for (int j = 1; j < R; ++j) {
                bucketCapacity[j] = bucketCapacity[j - 1] + bucketCapacity[j];
            }
            // 存儲進桶
            for (int j = array.length - 1; j >= 0; --j) {
                int k = array[j] / dec % R; 
                tempArray[bucketCapacity[k] - 1] = array[j];
                --bucketCapacity[k];  
            }
            // 寫出
            for(int j = 0; j < array.length; ++j) {
                array[j] = tempArray[j];
            }
            // 下一位
            dec *= 10;
        }
        
    }
    //求數組元素的最大位數
    private static int maxBit(int[] array) {
        int bit = 1;
        int dec = 10;
        for (int i = 0; i < array.length; ++i) {
            while (array[i] >= dec) {
                ++bit;
                dec *= 10;
            }
        }
        return bit;
    }
}
複製代碼