前言
常见的折半算法莫过于折半查找和折半插入排序,我们在此将他们的一些特点加以提炼,剖析,对比,以此实现更好的理解这种分组简化,提高效率的思想。
基本思想
折半插入排序是建立在折半查找的基础之上的,所以在此我们先分析折半查找。
什么叫折半?其实在数学上这就叫二分法。对于一个已经有序的数组(你可以用其他方法排序,比如选择或者冒泡),这个数组中的数就像数轴上一条线段,你只要将待查的关键字(key)与中点比较大小,就可以知道key对应的这个点是落在线段的左半部分还是右半部分。之后,我们再重复这个操作,这样我们的区间就会不断缩小,最后锁定在一个数上。然后我们就会看出来,是找到了,还是没有。
二分法(折半查找)需要三个指针,right(high),left(low),mid(middle),其中前两个指针衡量查找区间的范围,mid指针实现二分(中点)。(当然,在数组里,这些指针就是index(下标)的值)
这么一来折半插入排序就很容易说明了,他就是把插入排序(先检索有序部分,再选择合适的位置插入)的遍历检索部分替换为折半查找。也就是说,先折半查找,再插入。
细节
(1 )指针移动
每次折半,可以归结为三种情形(以从小到大排列的数组为例)
1.a[mid]=key,找到;
2.a[mid]<key,那么key在右半侧,只要保持right不动,left=mid+1即可;
3.a[mid]>key,这与2.恰好相反,right=mid-1;
对于折半插入排序,我们把1与2合并,至于为什么,接下来会讲。
(2)算法终点与稳定性
"折半"当然拥有高效率,但是他的终点却值得思考。
众所周知,二分法只有指定一个目标精确度,才能确定最小区间,才能有一个终点。
“折半”同理,只不过,折半处理的对象——数组是散点,使得这个终点确定更加容易。
我们用极限思维,当左右指针都指向一个数之后,还要进行最后一次比对,确定查找位置,在这之后无论是2.情况还是3.情况,Left都会移到right右边一位。
所以(left<=right)是终点条件。
把情况1合并,是为了输出,在折半插入排序中,我们以局部数组5,6,7(left指5,right指7,插入一个后方的6为例),进行试验,
若1.同2.合并:
a[mid]=key(6=6),left指向7,之后a[mid]=a[right]=a[left]>key,right指向6,到此为止,从right+1=left处开始插入。
若1.同3.合并:
a[mid]=key(6=6),right指向5,之后a[mid]=a[right]=a[left]<key,left指向6,到此为止,从right+1=left处开始插入
情况十分清楚了,只有1.同2.合并,该算法才是稳定的,6,6相对顺序不会交换,这也是为人们所选择的。
代码实现
运行结果
the end
活动地址:CSDN21天学习挑战赛