二分法插入排序:
在上一篇文章排序算法:插入排序中,介绍了插入排序。其中,插入排序的“插入”二字体现于在寻找有序区间[R0,Ri-1]内第一个比Ri小的Rx,然后将Ri插入Rx之后,如果Ri>Ri-1,那正好,Ri不需要再与有序区间的其他元素比较。
二分法插入排序沿用了插入排序的思路,而且由于[R0,Ri-1]是有序序列,在寻找Ri的插入位置时,可以采用二分查找法搜索有序区间中比第一个Ri小的元素,这样就减少了比较次数,提高了插入排序算法的性能。
以长度为6的序列 {6,3,5,4,1,2} 的二分法插入排序过程做示范:
第一趟排序:[3 6] 5 4 1 2 (3插入6之前)
第二趟排序:[3 5 6] 4 1 2 (5插入6之前)
第三趟排序:[3 4 5 6] 1 2 (4插入5之前)
第四趟排序:[1 3 4 5 6] 2 (1插入3之前)
第五趟排序:[1 2 3 4 5 6] (2插入3之前)
(注:用中括号括起来的是有序区间,之后的元素序列为待排区间)
可以看见二分法插入的排序过程和插入排序的过程是一摸一样的,但是其中寻找插入位置的过程是不一样的。
用第5趟排序过程作详细介绍第5趟排序过程需要寻找R5,即2的插入位置:
第五趟排序前的序列:[1 3 4 5 6] 2
首先,定义右边界right为R4,值为6,左边界为R0,值为1。[R0,R4]的中间元素为R(4+0)/2 = R2,值为4,2比中间元素小,因此元素2的插入位置一定在[R0,R2]之间,这时右边界置为中间元素的前一位,R1。
[R0,R1]的中间元素为R(1+0)/2 = R0,值为1,2比1大,因此元素2的插入位置应该在R0之后,这时将左边界置位中间元素的后一位,即R1。
此时搜寻的区间变为[R1,R1],中间元素也为R1,值为3,2小于R1,置右边届为中间元素前一位,即R0,左边界的位置大于了右边届,比较结束。此时的左边界R1即为2的插入位置。
将2插入序号1的位置上,序列由:[1 3 4 5 6] 2 变为:[1 2 3 4 5 6]。
使用二分查找法后,一共经过了3次比较找到插入位置。直接插入算法则需要5次比较(分别与6,5,4,3,1比较),可见二分查找法减少了插入发排序过程中比较的次数。
本文根据上述的二分法插入排序思路给出C++与Java的代码实现,并且使用Java对二分法插入排序算法和排序算法:插入排序中介绍的插入排序算法、以及排序算法:选择排序中介绍的选择排序算法,和排序算法:冒泡排序中介绍的两种冒泡排序算法进行性能比较。
C++代码: