二分插入排序(折半插入排序)

153 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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)

稳定性同样是和我们比较条件有关,表现为稳定