持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天
二分插入排序(折半插入排序)
有了直接插入排序的基础,我们大概可以明白插入排序的简单思路:将数组分为有序和无序两组,一开始有序组中只有一个数组元素,随着在无序组中不断抽取,向有序组中比较后插入,一步步将整个数组变为有序。
现在的问题就是:我从无序组中抽出元素,怎么查找要在有序组的哪一部分插入呢?
直接插入排序说:我直接从有序组的最后一个元素找起,只要满足排序条件(比它大或比它小)就替换,一步一步走到合适的位置。
[2,3,4,1,5,6]
假设前三个元素[2,3,4]是已经排序的有序组,后三个元素[1,5,6]是待排序的无序组
现在轮到元素 1 在有序组中插入,它会逐个比较,先和4比,发现比4小,就会与4交换位置,接下来再和3比,再和2比,最终插入到2的前面
二分插入排序说:人如其名,说二分,就一分为二,我从中间开始找。
[2,3,4,1,5,6]
还是刚刚的例子,我要为 1 在[2,3,4]这个有序组中寻找合适的地方插入,我不从最后一项开始找,我从中间开始找
有序组长度为3,我就从3/2=1(小数抹去或四舍五入均可,我这里选择抹去)的地方开始找,也就是从下标为1的元素(3)开始比起,发现比3小,我就再向左取中值,1/2=0,与下标为0的元素(2)进行比较,最终插入到它合适的位置
实现
function BinaryInsertionSort(nums){
for(let i = 1;i < nums.length;i++){
let left = 0;
let right = i;
for(let mid = Math.floor(right/2);left <= right;mid = Math.floor((left + right)/2)){
if(nums[i] > nums[mid]){
left = mid + 1;
}else{
right = mid - 1;
}
}
//插入
let temp = nums[i];
for(let j = i;j > left;j--){
nums[j] = nums[j-1];
}
nums[left] = temp;
}
}
时空复杂度及稳定性
二分插入排序的时间复杂度依旧是O(n^2),但在排序数量比较大的情况下,平均性能比直接插入排序要好(不过最坏情况会比直接插入排序的最好情况要差
空间复杂度为O(1)
稳定性同样是和我们比较条件有关,表现为稳定