折半插入排序(Binary Insertion Sort),也叫二分插入排序,是直接插入排序的一种改进,关于直接插入排序,可以点击【传送门】排序——直接插入排序查看,这里主要总结一下折半插入排序。
折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
以一个大小为n的数组arr为例,折半插入排序的基本思路为:
- 将未排序数组可以看做已排序区间[0,i-1]和未排序区间[i,n-1],同时定义已排序区间首尾分别为:low= 0,high= i-1;(第一次插入时默认第一个元素arr[0]为有序区间,此时low,high都为0,i为1)
- 我们需要将未排序区间的元素依次取出来插入到已排序区间的正确位置,这时,我们可以将已排序区间也看做由[0,mid]和[mid+1,i-1]两部分组成,mid是已排序区间的中间元素的位置;
- 从未排序区间第一个元素开始,如果发现要插入的第一个元素arr[i]大于已排序区间mid位置的元素,即mid位置之前的元素全部小于待插入元素,待插入元素必然在mid之后,所以更新low = mid+1;
- 若要插入的第一个元素arr[i]小于或等于已排序区间mid位置的元素,待插入元素必然在mid之前,所以更新high = mid-1;
- 直到low大于或等与high时,此时high位置之前的元素小于待插入元素且有序,插入只改变high位置之后的元素;
- 此时high位置就待插入元素的最终位置,在插入元素之前需要由后往前待排序区间的[high+1,i]区间的元素全部向后移动;
- 将待插入元素插入到high的位置;
- 此时一个元素插入完成,已排序区间大小加一,待排序区间大小减一,继续依次方法插入待排序区间剩余的元素即可
时间复杂度,空间复杂度,稳定性
折半插入排序是直接插入排序的改进,它的时间复杂度,空间复杂度,稳定性与直接插入排序相同(只是比较此数不同),分别为:
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 稳定性:稳定
代码:
import java.util.Arrays;
/**
* 二分(折半)插入排序:
* 时间复杂度:O(n^2)
* 空间复杂度:O(1)
* 稳定性:稳定
* */
public class InsertSort {
public static void main(String[] args){
int[] arr = {5,2,-6,8,-3,9,7,4,1,0,-5,3,6};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
MyBinaryInsertSort(arr);
System.out.println("MyInsertSort-排序后:");
System.out.println(Arrays.toString(arr));
}
public static void MyBinaryInsertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int low = 0;
int high = i-1;
int tmp = arr[i];
int mid = 0;
int j = i-1;
while(low<=high){
mid = (low+high)/2;
if(tmp>arr[mid]){
low = mid+1;
}else{
high = mid-1;
}
}
for(;j>high;j--){
arr[j+1] = arr[j];
}
arr[j+1] = tmp;
}
}
与直接插入排序对比:
折半插⼊排序在数据集⽆序的情况下要优于直接插⼊排序,但是在近乎有序的数据集下,由于插⼊排序只⽐较⼀次,因此最好情况下的直接插⼊排序要优于折半插⼊排序。