快速排序+堆排序+归并排序学习

3 阅读2分钟

1、快速排序

双指针快排,能搞定含有大量重复元素和序列基本有序的情况。

class Solution {
    public int[] sortArray(int[] nums) {
        int n = nums.length;
        quicksort(nums, 0, n - 1);
        return nums;
    }

    void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    void quicksort(int[] nums, int l, int r) {
        if(l >= r) {
            return;
        }
        int index = (int) (Math.random() % (r - l + 1)) + l;
        swap(nums, r, index);
        int i = l, j = r - 1;
        int x = nums[r];
        while(i <= j) {
            while(i <= j && nums[i] < x) {
                i++;
            }
            while(i <= j && nums[j] > x) {
                j--;
            }
            if(i <= j) {
                swap(nums, i, j);
                i++;
                j--;
            } 
        }
        swap(nums, r, i);
        quicksort(nums, l, i - 1);
        quicksort(nums, i + 1, r);
    }
}

技巧就是单趟排序的时候使用首尾双指针,这样即便元素都一样,两个指针相遇位置也是中间,本次排好的pivot位于序列中间,左右两个序列长度平衡,有效避免了极端情况。使用随机数pivot可以解决一般的原序列基本有序的情况。

2、归并排序
class Solution {
    int[] temp;
    public int[] sortArray(int[] nums) {
        int n = nums.length;
        temp = new int[n];
        mergeSort(nums, 0, n - 1);
        return nums;
    }

    void mergeSort(int[] nums, int l, int r) {
        if(l >= r) {
            return;
        }
        int mid = (r - l) / 2 + l;
        mergeSort(nums, l, mid);
        mergeSort(nums, mid + 1, r);

        int i = l, j = mid + 1;
        int index = 0;
        while(i <= mid && j <= r) {
            if(nums[i] <= nums[j]) {
                temp[index++] = nums[i++];
            } else {
                temp[index++] = nums[j++];
            }
        }
        while(i <= mid) {
            temp[index++] =  nums[i++];
        }
        while(j <= r) {
            temp[index++] = nums[j++];
        }
        for(int k = 0; k < r - l + 1; k++) {
            nums[k+l] = temp[k];
        }
    }
}
3、堆排序

先构造大根堆,将堆末尾的元素与堆顶进行交换后,重新维护大根堆。循环直至排序完成。

class Solution {
    public int[] sortArray(int[] nums) {
        heapSort(nums);
        return nums;
    }
    
    void heapSort(int[] nums) {
        buildMaxHeap(nums);
        for(int i = 0; i < nums.length; i++) {
            swap(nums, 0, nums.length - 1 - i);
            maxHeapify(nums, 0, nums.length - 1 - i);
        }
    }

    void buildMaxHeap(int[] nums) {
        for(int i = nums.length / 2; i >= 0; i--) {
            maxHeapify(nums, i, nums.length);
        }
    }

    void maxHeapify(int[] nums, int i, int n) {
        int left = 2 * i + 1;
        int right = left + 1;
        int mid = i;

        if(left < n && nums[left] > nums[mid]) {
            mid = left;
        }
        if(right < n && nums[right] > nums[mid]) {
            mid = right;
        }

        if(mid != i) {
            swap(nums, mid, i);
            maxHeapify(nums, mid, n);
        }
    }

    void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}