总览

参考:https://www.cnblogs.com/onepixel/articles/7674659.html

冒泡:每次将最小的放到前面

插入:构造有序序列,没排序的在排序好的序列中,从后往前扫描,插入

选择:每次把最大的放到后面

希尔:根据间隔将数组分成多部分,对每个部分进行插入排序;需要对增量间隔把控的很好

快速:随机选取数组中一个值作为基准,将比基准大的都放在右边,比基准小的放在左边,再分别对左、右序列迭代,不稳定,时间nlogn,可能n2,空间

归并:采用分治法,将有序的子序列合并,得到完全有序的序列,稳定,时间nlogn,空间n

计数:将数值当做为数组下标,数组的值是出现的次数

基数:低位0-9排到对应下标数组中,从低位到高位

:计数排序的升级,利用函数映射关系,根据值确定桶,在桶里排序

:利用堆结构进行排序,堆是接近完全二叉树的结构,子节点的总是小于(大于)父节点

稳定:冒泡、插入、归并

不稳定:希尔、快速、选择、堆排序

img

快速排序

解题思路

数组中随机选择一个值基准,将所有比基准小的值放在其左边,比基准大放在其右边
[ [比基准小的数据] 基准 [比基准大的数据] ]
分别对基准的左右部分迭代,得到有序数组。

基准左右分离

假设取数组最左边(arr[low])为基准,保存为temp

  1. 从右边high下标开始,high–,找到比基准小的(说明其不该在右边)值,存放进arr[low]
  2. 再从左边low下标开始,low++,找到比基准大的(说明其不该在左边)值,存放进arr[high]

在1、2中循环,当 high 等于 low时,说明已经成功分离出比基准大的和比基准小的:
[ [比基准小的数据] 基准 [比基准大的数据] ]
将 temp存入 arr[low]即完成基准左右分离

迭代

每次[比基准小的数据]、[比基准大的数据]看成一个普通的数组,也采取基准左右分离的方法进行迭代,最终可获得递增的数组

随机基准

我们应当选择基准时是随机的,在low和high之间选择随机下标,使用new Random().nextInt(n)可以获取随机数,其范围为[0,n)
我们要获取的是[low, high],则应当为low + new Random().nextInt(high - low + 1)
将获取到的基准与arr[low]交换,开始基准左右分离

坏情况2

每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。

代码

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

    public void quickSort(int[] nums, int low, int high) {
        if( low < high) &#123;
            int index = getIndex(nums, low, high);
            quickSort(nums, low, index - 1);
            quickSort(nums, index + 1, high);
        &#125;
    &#125;

    public int getIndex(int[] nums, int low, int high) &#123;
        // low, high获取随机基准
        int index = low + new Random().nextInt(high - low + 1);
        // 把基准放到第一个
        int temp = nums[index];
        nums[index] = nums[low];
        nums[low] = temp;
        // 开始移动
        while(low < high) &#123;
            // 比基准>=的,high一直左移
            while(low < high && nums[high] >= temp) &#123;
                high--;
            &#125;
            // 遇到小的了,把它移到前面
            nums[low] = nums[high];
            // 比基准<=的,low一直右移
            while(low < high && nums[low] <= temp) &#123;
                low++;
            &#125;
            nums[high] = nums[low];
        &#125;
        // low 和 high 为分界
        nums[low] = temp;
        return low;
    &#125;
&#125;

归并排序

将数列递归拆分为两部分,再逐步合并成整体

public void sort(int[] nums, int low, int high) &#123;
    int mid = low + (high -low) /2;
    if(low < high) &#123;
        sort(nums, low, mid);
        sort(nums, mid +1, high);
        merge(nums, low, high, mid);
    &#125;
&#125;
public void merge(int[] nums, int low, int high, int mid) &#123;
    int[] tempRes = new int[high -low +1];
    int lowIndex = low;
    int highIndex = mid +1;
    int resIndex = 0;
    while(lowIndex <= mid && highIndex <= high) &#123;
        if(nums[lowIndex] <= nums[highIndex]) &#123;
            tempRes[resIndex++] = nums[lowIndex++];
        &#125; else &#123;
            tempRes[resIndex++] = nums[highIndex++];
        &#125;
    &#125;
    while(lowIndex <= mid) &#123;
        tempRes[resIndex++] = nums[lowIndex++];
    &#125;
    while(highIndex <= high) &#123;
        tempRes[resIndex++] = nums[highIndex++];
    &#125;
    for (int i = 0; i < tempRes.length; i++) &#123;
        nums[i +low] = tempRes[i];
    &#125;
&#125;

希尔排序

public int[] shellSort(int[] nums) &#123;
    int len = nums.length;
    // 间隔为一半
    for(int gap = len /2; gap > 0; gap /= 2) &#123;
        for(int i = gap; i < len; i++) &#123;
            int current = nums[i];
            int preIndex = i -gap;
            while(preIndex >= 0 && current < nums[preIndex]) &#123;
                nums[preIndex +gap] = nums[preIndex];
                preIndex -= gap;
            &#125;
            nums[preIndex +gap] = current;
        &#125;
    &#125;
    return nums;
&#125;