插入排序

插入排序

基本思想:

每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

常用算法:

  1. 直接插入排序
  2. 折半插入排序(二分法)
  3. 希尔排序(缩小增量排序):Shell

直接插入排序

基本思想

每步将一个待排序的元素,按其排序码大小,插入到前面已经排好序的一组元素的适当位置上, 直到元素全部插入为止。

基本方法

当插入第i (i≥1) 个元素时,前面的V[0], V[1], …, V[i-1]已经排好序。这时,用V[i]的排序码与V[i-1], V[i-2], …的排序码顺序进行比较,插入位置即将V[i]插入,原来位置上的元素向后顺移。

复杂度和稳定性

时间复杂度:Ω (n)和O(n2)

空间复杂度:O(1)

稳定性:稳定

代码

static void insertSort(int[] nums){
        for (int i = 1; i < nums.length; i++){
            if (nums[i] < nums[i - 1]){
                int tmp = nums[i];
                int j = i - 1;
                do{
                    nums[j + 1] = nums[j];
                    j--;
                }while(j >= 0 && tmp < nums[j]);
                nums[j + 1] = tmp;
            }
        }
    }

折半插入排序

基本思想

设在顺序表中有一 个元素序列 V[0], V[1], …, V[n-1]。其中, V[0], V[1], …, V[i-1] 是已经排好序的元素。在插入V[i] 时, 利用折半搜索法寻找V[i] 的插入位置。

复杂度和稳定性

时间复杂度:Ω (n)和O(n2)

空间复杂度:O(1)

稳定性:稳定

折半插入和直接插入复杂度一样,但是折半插入一般情况下排序码比较次数较少,性能一般比直接排序快。

代码

static void binaryInsertSort(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < nums[i - 1]) {
                int tmp = nums[i];
                int low = 0;
                int high = i - 1;
                while (low <= high) {
                    int mid = (low + high) / 2;
                    //最终nums[low]刚好>=tmp
                    if (nums[mid] < tmp)
                        low = mid + 1;
                    else
                        high = mid - 1;
                }
                for (int j = i; j > low; j--) {
                    nums[j] = nums[j - 1];
                }
                nums[low] = tmp;
            }
        }
    }

希尔排序

基本思想

​ 设待排序元素序列有 n 个元素, 首先取一个整数 gap < n 作为间隔,将全部元素分为 gap 个子序列,所有距离为 gap 的元素放在同一个子序列中,在每一个子序列中分别施行直接插入排序。
​ 然后缩小间隔 gap, 例如取 gap = gap/2 + 1,重复上述的子序列划分和排序工作。直到最后取 gap == 1,将所有元素放在同一个序列中排序为止。

复杂度和稳定性

Knuth利用大量实验统计资料得出 : 当 n 很大时,排序码平均比较次数和元素平均移动次数大约在 n1.25 到 1.6*n1.25 的范围内。这是在利用直接插入排序作为子序列排序方法的情况下得到的。

稳定性:不稳定

代码

static void shellSort(int[] nums){
        int gap = nums.length;
        do{
            gap = gap/3 + 1;
            for (int i = gap; i < nums.length; i++){
                if (nums[i] < nums[i - gap]){
                    int tmp = nums[i];
                    int j = i - gap;
                    do{
                        nums[j + gap] = nums[j];
                        j -= gap;
                    }while(j >= 0 && tmp < nums[j]);
                    nums[j + gap] = tmp;
                }
            }
        }while (gap > 1);
    }
posted @ 2020-04-04 19:02  心流flux  阅读(367)  评论(0)    收藏  举报