排序——插入类排序(直接插入排序、折半插入排序、希尔排序)

有序序列 r[1]~r[i-1]   r[i]   无序序列 r[i+1]~r[ n]

一趟插入排序的任务:

  1. 在 r[1]~r[i-1] 有序序列区中查找 r[i] 的插入位置,保证 r[1...j] <= r[i] < r [j+1... i-1]。
  2. 将 r [j+1... i-1] 中所有的记录向后移一个位置。
  3. 将 r[i] 插入到 r[j+1]。

插入排序分类:

  • 直接插入排序(基于顺序查找)
  • 折半插入排序(基于折半查找)
  • 希尔排序(基于逐趟缩小增量)

 

1.  直接插入排序

直接插入排序是利用顺序查找来确定 r[ i ] 在 r[ 1 ... i-1]有序序列区中的插入位置。

直接插人排序的步骤如下:

  1. 从 r[ i-1 ] 起向前进行顺序查找。
  2. 在查找过程中将小于 r[ i ] 的元素可以同时向后移动。
  3. 第1个元素视为已排好序的记录,从第 2 个记录开始进行插入。
package com.zth.sort;

import java.util.Arrays;

public class InsertSort {
    public static void main(String[] args){
        Integer [] array1 = {3,2,5,8,4,7,6,9};
        insertSort(array1);
        System.out.println(Arrays.toString(array1));

        Double[] array2 = {3.3,2.3,5.3,8.3,4.3,7.3,6.3,9.3};
        insertSort(array2);
        System.out.println(Arrays.toString(array2));
    }

    private static <AnyType extends Comparable<? super AnyType>>
    void insertSort(AnyType[] array){

        AnyType temp;
        int j;

        for (int i = 1; i < array.length; i++) {
            temp = array[i];
            for (j = i-1; j >=0 && temp.compareTo(array[j])< 0 ; j--) {
                array[j+1] = array[j];
            }
            array[j+1] = temp;
        }
    }

}

 

算法性能分析:

时间复杂度空间复杂度稳定性
平均情况最坏情况最好情况
o(n^2)o(n^2)o(n)o(1)稳定

2. 折半插入排序

对于一个有序表来说,折半查找的性能优于顺序查找,因而在 r[ 1 ]~r [ i-1 ] 这个有序序列中确定 r[ i ] 的插入位置时,可以利用折半查找实现该位置 的确定。

package com.zth.sort;

import java.util.Arrays;

public class BiInsertSort {
    public static void main(String[] args){
        Integer [] array1 = {3,2,5,8,4,7,6,9};
        biInsertSort(array1);
        System.out.println(Arrays.toString(array1));

        Double[] array2 = {3.3,2.3,5.3,8.3,4.3,7.3,6.3,9.3};
        biInsertSort(array2);
        System.out.println(Arrays.toString(array2));
    }

    private static<AnyType extends Comparable<? super AnyType>>
    void biInsertSort(AnyType[] array){
        AnyType temp;
        int j;

        for (int i = 1; i<array.length; i++) {
            temp = array[i];
            /**
             * 二分查找
             */
            int low = 0;
            int high = i-1;
            while(low <= high){

                int mid = (low + high)/2;
                if (array[mid].compareTo(temp) >0){
                    high = mid-1;
                }else {
                    low = mid +1;
                }
            }
            /**
             * 移动元素
             */
            temp = array[i];
            for ( j = i-1; j >=low; j--) {
                array[j+1] = array[j];
            }
            array[j+1] = temp;
        }
    }
}

采用折半插入排序算法,可以减少关键字的比较次数。

每插入一个元素,需要比较的次数最多的情况下为折半判定树的深度。

虽然减少了比较次数,但是没有改变移动次数,所以时间复杂度仍为 o (n^2)。

空间复杂度、稳定性等都与直接插入排序一样。

3.  希尔排序

希尔排序又称为 缩小增量排序。

基本思想:

先将整个待排元素序列分割成若干个子序列(有相隔某个增量的元素组成),分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

图片来源(http://www.cnblogs.com/jingmoxukong/p/4303279.html

package com.zth.sort;
import java.util.Arrays;

/**
 * @author 时光·漫步 
 * 希尔排序
 */
public class ShellSort {
    public static void main(String[] args){
        Integer [] array1 = {3,2,5,8,4,7,6,9};
        shellSort(array1);
        System.out.println(Arrays.toString(array1));
    }
    private static <AnyType extends Comparable <? super AnyType>>
    void shellSort(AnyType[] array){
        int j;

        for (int gap = array.length/2; gap >0 ; gap /= 2) {
            // 把距离为 gap 的元素分为一个组,扫描所有组
            for (int i = gap; i < array.length; i++) {
                AnyType temp = array[i];
                // 对距离为 gap 的元素进行排序
                for (j = i-gap; j >= 0 && temp.compareTo(array[j])< 0  ; j -= gap) {
                    array[j + gap] = array[j];
                }
                array[j + gap] = temp;
            }
        }
    }
}

性能分析:

时间复杂度空间复杂度稳定性
平均情况最坏情况最好情况o(1)不稳定
o(n log n)o(n^2)o(n^2/3)

 

4.  直接插入排序和希尔排序的比较

  1. 直接插入排序是稳定的;而希尔排序是不稳定的。
  2. 直接插入排序更适合于原始记录基本有序的集合。
  3. 希尔排序的比较次数和移动次数都要比直接插入排序少,当N越大时,效果越明显。  
  4. 在希尔排序中,增量序列 gap 的取法必须满足:最后一个步长必须是 1 。 
  5. 直接插入排序也适用于链式存储结构;希尔排序不适用于链式结构。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值