三大排序算法总结

三大排序算法: 快速排序, 堆排序, 归并排序

912. 排序数组
冒泡排序: 10个数字,需要9次循环,每次排序出一个最大值,最后一个元素自动排序.

  • 快速排序
    建立基准pivot,根据基准左右分割进行排序
  • 堆排序
    构建二叉树,保持父节点数值总是大于等于子节点的数值, 可以直接使用原数组构建树结构,left = 2 * i +1; right = 2 * i + 2; 索引i的左右孩子节点的索引关系
  • 归并排序:
    分治法, (将序列划分两部分再将每一部分排序), 将每一部分一直划分, 直到只有一个元素为止, 两个各一个元素进行行合并=> 形成有序序列, 再将有序序列合并, 排序成功,
    分治法: 使用后序递归思路, 先分, 对根节点进行处理
    Java代码实现
// 快速排序
class Solution {
    // 比较: 比pivot小, 交换到前面, 交换pivot, 返回pivot位置
    private int partition(int[] nums, int left, int right) {
        int pivot = left;
        int index = pivot + 1;
        for (int i = index; i < right + 1; i++) {

            if (nums[i] < nums[pivot]) {
                int temp = nums[i];
                nums[i] = nums[index];
                nums[index] = temp;
                index++;
            }
        }
        int temp = nums[index - 1];
        nums[index - 1] = nums[pivot];
        nums[pivot] = temp;
        return index - 1;
    }

    // 先比较, 再划分(先序遍历过程)
    private void quickSort(int[] nums, int left, int right) {
        if (left < right) {
            int pivot = partition(nums, left, right);
            quickSort(nums, left, pivot - 1);
            quickSort(nums, pivot + 1, right);
        }
    }

    public int[] sortArray(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        quickSort(nums, left, right);
        return nums;
    }
}

// 堆排序
static class Solution2 {
    // 调整所有的父节点(验证是否>=子节点), 逆向遍历, nums.length / 2
    private void buildHeap(int[] nums) {
        for (int i = (nums.length / 2) - 1; i >= 0; i--) {
            adjustHeap(nums, nums.length - 1, i);
        }
    }
    // 调整堆: 最大节点换到父节点上, 后序递归交换
    private void adjustHeap(int[] nums, int rightIndex, int index) {
        int left = index * 2 + 1;
        int right = index * 2 + 2;
        int largestIndex = index;
        if (left <= rightIndex && nums[left] > nums[largestIndex]) {
            largestIndex = left;
        }
        if (right <= rightIndex && nums[right] > nums[largestIndex]) {
            largestIndex = right;
        }
        if (largestIndex != index) {
            int temp = nums[index];
            nums[index] = nums[largestIndex];
            nums[largestIndex] = temp;
            adjustHeap(nums, rightIndex, largestIndex);
        }
    }
    // 堆排序: 不断交换根节点
    private void heapSort(int[] nums) {
        int rightIndex = nums.length - 1;
        buildHeap(nums);
        for (int i = 0; i < nums.length; i++) {
            // 交换根节点nums[0], 和尾节点 nums[right]; 删除尾节点(right--), 调整堆
            int temp = nums[0];
            nums[0] = nums[rightIndex];
            nums[rightIndex] = temp;
            rightIndex--;
            adjustHeap(nums, rightIndex, 0);
        }
    }

    public int[] sortArray(int[] nums) {
        heapSort(nums);
        return nums;
    }
}

// 归并排序
class Solution3 {
    // 归并排序, 先划分再排序(后序遍历过程), 回到根节点再处理: 0, 1, 2
    private int[] mergeSort(int[] nums) {
        if (nums.length <= 1) return nums;
        int mid = nums.length / 2;
        // [0,mid), [mid, endIndex]
        int[] left = mergeSort(Arrays.copyOfRange(nums, 0, mid));
        int[] right = mergeSort(Arrays.copyOfRange(nums, mid, nums.length));
        return merge(left, right);
    }

    // 将有序序列left和right进行合并, 长度会发生变化所以需要增加空间
    private int[] merge(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        int i = 0, j = 0;
        for (int rIndex = 0; rIndex < result.length; rIndex++) {
            if (i >= left.length) {
                result[rIndex] = right[j++];
            } else if (j >= right.length) {
                result[rIndex] = left[i++];
            } else if (left[i] < right[j]) {
                result[rIndex] = left[i++];
            } else {
                result[rIndex] = right[j++];
            }
        }
        return result;
    }

    public int[] sortArray(int[] nums) {
        nums = mergeSort(nums);
        return nums;
    }
}

参考

  1. 10大经典排序算法总结
  2. 外部排序
posted @ 2021-12-18 22:07  -Rocky-  阅读(152)  评论(0编辑  收藏  举报