插入排序

插入排序

最基本的排序,很多书上的说法“就像我们平时打牌一样”,原理很简单

a 为一组牌 共 n 张,升序排列
(1)将第 i 张牌与前 i-1 张排好序的牌比较,(方向向前)
(2)找到应在的位置 k (a[k] < a[i]),将 k + 1i - 1 张牌向后挪一张。
(3)把第 i 张牌放入 位置 k+1

这是我的代码

public static void sort(int[] data){
        int key = 0,j=0;
        for(int i = 1; i < data.length; i ++){
            key = data[i];
            j = i -1;
            while(j > 0 && data[j] > key){
                data[j + 1] = data[j];
                j --;
            }
            data[j + 1] = key;
        }
    }
时间复杂度

最好情况下, 即 数组已有序 , 的时间复杂度为 O( n ) ;
最坏情况下, 即 数组倒叙, 的时间复杂度为 O( n2 ) ;
平均时间复杂度为 O( n2 ) ;

折半插入

插入排序的最好情况很理想,是线性的,但平均情况却非常差,幸好有一种改进的方法,折半。在一般的插入过程中寻找位置 k 的过程是逐一的向前查找,但我们注意到 i 之前的牌堆是有序的,正好符合折半查找的前提。利用折半的方式可以使每次的查找复杂度从 O( n ) 降为 O( log(n) )
但无法避免的是,还要将 i - k 个数向后移动。所以折半插入的时间复杂度任然为O( n2 )

我的代码

public static void sort(int[] data){
        int key = 0,m = 0,low = 0,high =0;
        for(int i = 1; i < data.length; i ++){
            key = data[i];
            low = 0;
            high = i - 1;
            while(low <= high){       //折半查找
                m = (low + high) / 2;
                if(data[m] > key){
                    high = m - 1; 
                }else{
                    low = m + 1;
                }
            }
            for(int j = i - 1; j >= high + 1; j --){
                data[j + 1] = data[j];
            }
            data[high + 1] = key;
        }
    }
希尔排序

希尔排序,又叫“减少增量排序”,它在插入排序的基础上做了极大的改进。
分析一下插入排序的特征,

  1. 在最好情况下,即已排序的情况下,时间复杂度是线性的。那么如果数组“基本有序”就会大大提高插入排序的效率。
  2. 算法简单,当 n 值较小时效率较高

这就是希尔排序的思想。将整个数组分成若干组,分别进行插入排序,再合并若干组,再排序。逐渐逼近“有序”,直到合为一个数组。
而且希尔排序的分组,不是简单的切割数组,而是将相隔一定“增量”的数分为一组。
原理如下

取合适增量 d
将数组中 同一增量上的数进行出入排序
减小 增量 d,再排序 , 直到 d = 1

我的代码如下

public static void sort(int[] data){
         int d=data.length;
         while(true)
         {
             d=d/2;     //逐渐减小增量
             for(int x=0;x<d;x++)
             {
                 //进行插入排序
                 for(int i=x+d;i<data.length;i=i+d)
                 {
                     int temp=data[i];
                     int j;
                     for(j=i-d;j>=0&&data[j]>temp;j=j-d)
                     {
                         data[j+d]=data[j];
                     }
                     data[j+d]=temp;
                 }
             }
             if(d==1)   // 直到增量为 1
             {
                 break;
             }
         }
    }

希尔排序的复杂度不好分析,涉及到数学上尚未解决的问题。

有人指出,当增量序列为 dlta[k]=2tk+11 时,希尔排序的时间复杂度为 O( n3/2 )

希尔排序中“增量”的选择是影响其效率的主要因素。而增量序列的确定也是非常复杂的,这里不做讨论,又兴趣的可以研究一下。


参考文献:
[1] 严蔚敏 吴伟民 . 数据结构(C语言版) . 清华大学出版社
[2] 邹恒明 . 算法之道 . 机械工业出版社
[3] 算法导论 . 机械工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值