折半插入排序之边界分析

折半插入排序的基本思想是,从已排好序的子数组中快速查找待插入点。

设计折半插入排序的难点在于对边界的处理,怎么判断循环终止条件可以保证没有错误,并且更加清晰和有条理。


为描述方便,设插入元素的关键字为 v,关键字数组为 K。

规定若 v < K[ m ],找低半区; 若 v >= K[m],找高半区。子数组下标从 1 开始,长度为 len。


当子数组变成只有两个元素时,

不妨表示为:low  =  i; high = i+1;

此时:m = (low+high)/2 = i;


由于这样不对称的原因,如果用 [ low, m ] 和 [ m, high ] 两个半区来划分子数组 [ low, high ]。

高半区按这个规则划下去不会再缩减元素个数,始终保持两个。

所以若循环终止条件为 while( low < high ),就有可能产生死循环。


解决方案有:

1.改循环终止条件为 while( low < high-1),循环终止时,low  == high-1,可分成三类情况讨论:

①若 low == 1,表明 v < K[ high ],但 v 与 K[ 1 ] 还未比较过,此时若 v < K[ 1 ],插入点为 1,否则插入点为 2;

②若 high == len,表明 v >= K[ low ],但 v 与 K[ len ] 还未比较过,此时若 v < K[ len  ],插入点为 len,否则插入点为 len+1;

③其它情况,必然 K[ low ] <= v < K[ high ],则插入点为 high。


2.低半区不变,高半区改为[ m+1, high ]

可避免高半区死循环的发生,循环终止时,low  == high,那么,

若 v >= K[ high ],则插入点为 high+1,否则插入点为 high。


3.低半区改为[ low, m-1 ],高半区改为[ m+1, high ],循环终止条件改为 while( low <= high )

循环终止时,low  == high+1,插入点为 low。这是因为,在循环的最后一步中,m == low == high,那么,

若 v >= K[ m ],高半区 [ m+1, high ] 不包含任何元素,插入点就刚好在 m 的后边,即 m+1;

若 v < K[ m ],低半区 [ low, m-1 ] 也不包含任何元素,插入点就刚好在 m 的前边,即 m。

这两种情况下,插入点均等于 low,达到了统一。


综上所述,第 3 种方案在代码上最易实现,写法上简洁。

附方案3代码:

// 关键字数组 K 下标从 1 开始,K[0]作为哨兵,n 为关键字的个数
void BinInsertSort( int K[ ], int n )
{
    int i, j;
    int low, high, m;
    
    for( i = 2; i <= n; ++i ) {
        K[0] = K[i];
        low = 1; high = i-1;
        while( low <= high ){
            m = (low+high) / 2;
            if( K[0] < K[m] ) high = m-1;
            else low = m+1;
        }
        for( j = i-1; j >= low; --j)
            K[j+1] = K[j];
        K[low] = K[0];
    }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值