歸併排序、快速排序和堆排序的 Java 實現

歸併排序遞歸版

package sort;

public class MergeSortRecursively {
    public static void mergeSort(int[] array) {
        if (array == null || array.length <= 1)
            return;

        sort(array, 0, array.length - 1);
    }

    private static void sort(int[] array, int left, int right) {
        if (left >= right)
            return;

        int middle = left + (right - left) / 2;
        sort(array, left, middle);
        sort(array, middle + 1, right);
        merge(array, left, middle, right);
    }

    private static void merge(int[] array, int left, int middle, int right) {
        int length = array.length;
        int[] temp = new int[length]; // temp數組用於暫存合併的結果

        for (int i = 0; i < length; i++)
            temp[i] = array[i];

        int index = left, leftIndex = left, rightIndex = middle + 1;

        // 將記錄由小到大地放進temp數組
        while (leftIndex <= middle && rightIndex <= right) {
            if (array[leftIndex] <= array[rightIndex])
                temp[index++] = array[leftIndex++];
            else
                temp[index++] = array[rightIndex++];
        }

        // 接下來兩個while循環是爲了將剩餘的元素放到temp數組中
        while (leftIndex <= middle)
            temp[index++] = array[leftIndex++];
        while (rightIndex < right)
            temp[index++] = array[rightIndex++];

        // 將temp數組中的元素寫入到待排數組中
        for (int i = 0; i < length; i++)
            array[i] = temp[i];
    }
}

歸併排序迭代版

package sort;

public class MergeSortIteratively {
    public static void mergeSort(int[] array) {
        if (array == null || array.length <= 1)
            return;

        sort(array);
    }

    private static void sort(int[] array) {
        int length = array.length;
        int k = 1;

        while (k < length) {
            helper(array, k, length);
            k *= 2;
        }
    }

    // 將數組中的相鄰的有k個元素的序列進行歸併
    private static void helper(int[] array, int k, int length) {
        int i = 0;

        // 從前往後,將2個長度爲k的子序列合併爲1個
        while (i < length - 2 * k + 1) {
            merge(array, i, i + k - 1, i + 2 * k - 1);
            i += 2 * k;
        }

        // 這段代碼保證了,將那些“落單的”長度不足兩兩merge的部分和前面merge起來。
        if (i < length - k)
            merge(array, i, i + k - 1, length - 1);
    }

    private static void merge(int[] array, int left, int middle, int right) {
        int length = array.length;
        int[] temp = new int[length]; // temp數組用於暫存合併的結果

        for (int i = 0; i < length; i++)
            temp[i] = array[i];

        int index = left, leftIndex = left, rightIndex = middle + 1;

        // 將記錄由小到大地放進temp數組
        while (leftIndex <= middle && rightIndex <= right) {
            if (array[leftIndex] <= array[rightIndex])
                temp[index++] = array[leftIndex++];
            else
                temp[index++] = array[rightIndex++];
        }

        // 接下來兩個while循環是爲了將剩餘的元素放到temp數組中
        while (leftIndex <= middle)
            temp[index++] = array[leftIndex++];
        while (rightIndex < right)
            temp[index++] = array[rightIndex++];

        // 將temp數組中的元素寫入到待排數組中
        for (int i = 0; i < length; i++)
            array[i] = temp[i];
    }
}

快速排序

package sort;

public class QuickSort {
    public static void quickSort(int[] array) {
        if (array == null || array.length <= 1)
            return;

        sort(array, 0, array.length - 1);
    }

    public static void sort(int[] array, int left, int right) {
        if (right - left <= 0)
            return;

        int index = partition(array, left, right);
        sort(array, left, index - 1);
        sort(array, index + 1, right);
    }

    public static int partition(int[] array, int left, int right) {
        // 選擇第一個值作爲基準
        int pivot = array[left];
        while (left < right) {
            while (left < right && array[right] >= pivot) 
                right--;
            if (left < right)
                array[left] = array[right];
            while (left < right && array[left] < pivot) 
                left++;
            if (left < right)
                array[right] = array[left];
        }
        array[left] = pivot;
        return left;
    }
}

堆排序

package sort;

/**
 * 通常堆是通過一維數組來實現的,在數組起始位置爲 0 的情形中:
 * 父節點 i 的左子節點在位置 (2 * i + 1);
 * 父節點 i 的右子節點在位置 (2 * i + 2);
 * 子節點 i 的父節點在位置 floor((i − 1) / 2);
 */
public class HeapSort {
    public static void heapSort(int[] array) {
        if (array == null || array.length <= 1)
            return;

        sort(array);
    }

    private static void sort(int[] array) {
        for (int i = array.length / 2; i >= 0; i--)
            maxHeapify(array, i, array.length);

        // 將每個最大值的根節點與末尾元素交換,並且再調整二叉樹,使其成爲最大堆
        for (int i = array.length - 1; i > 0; i--) {
            swap(array, 0, i); // 將堆頂記錄和當前未經排序子序列的最後一個記錄交換
            maxHeapify(array, 0, i); // 交換之後,需要重新檢查堆是否符合最大堆,不符合則要調整
        }
    }

    private static void maxHeapify(int[] array, int index, int length) {
        int father, child;
        for (father = array[index]; leftChild(index) < length; index = child) {
            child = leftChild(index);

            // 如果左子樹小於右子樹,則需要比較右子樹和父節點
            if (child != length - 1 && array[child] < array[child + 1])
                child++; // 序號加1,指向右子樹

            // 如果父節點小於子結點,則需要交換
            if (father < array[child])
                array[index] = array[child];
            else
                break; // 最大堆結構未被破壞,不需要調整
        }
        array[index] = father;
    }

    // 獲取到左子結點
    private static int leftChild(int i) {
        return 2 * i + 1;
    }

    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

測試用例

package sort;

import java.util.Arrays;
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        int[] a1 = new Random().ints(10, 1, 100).toArray();
        QuickSort.quickSort(a1);
        System.out.println(Arrays.toString(a1));

        int[] a2 = new Random().ints(10, 1, 100).toArray();
        MergeSortIteratively.mergeSort(a2);
        System.out.println(Arrays.toString(a2));

        int[] a3 = new Random().ints(10, 1, 100).toArray();
        MergeSortRecursively.mergeSort(a3);
        System.out.println(Arrays.toString(a3));
        
        int[] a4 = new Random().ints(10, 1, 100).toArray();
        HeapSort.heapSort(a4);
        System.out.println(Arrays.toString(a4));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章