二分插入排序
使用二分查找优化插入排序的实现
问题
实现二分插入排序(拆半插入排序),在插入排序的基础上,使用二分查找来确定插入位置。
解答
基本思路
插入排序在查找插入位置时需要逐个比较,时间复杂度为 O(n)。二分插入排序利用已排序部分的有序性,用二分查找将查找插入位置的复杂度降为 O(log n)。
实现代码
function binaryInsertionSort(arr) {
const len = arr.length;
for (let i = 1; i < len; i++) {
const current = arr[i];
// 二分查找插入位置
let left = 0;
let right = i - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] > current) {
right = mid - 1;
} else {
left = mid + 1;
}
}
// left 就是插入位置,将 left 到 i-1 的元素后移
for (let j = i - 1; j >= left; j--) {
arr[j + 1] = arr[j];
}
// 插入元素
arr[left] = current;
}
return arr;
}
// 测试
const arr = [5, 2, 9, 1, 5, 6];
console.log(binaryInsertionSort(arr)); // [1, 2, 5, 5, 6, 9]
与普通插入排序对比
// 普通插入排序 - 边比较边移动
function insertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
const current = arr[i];
let j = i - 1;
// 查找和移动同时进行
while (j >= 0 && arr[j] > current) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = current;
}
return arr;
}
// 二分插入排序 - 先查找再移动
function binaryInsertionSort(arr) {
for (let i = 1; i < arr.length; i++) {
const current = arr[i];
// 1. 二分查找插入位置
let left = 0, right = i - 1;
while (left <= right) {
const mid = (left + right) >> 1;
if (arr[mid] > current) right = mid - 1;
else left = mid + 1;
}
// 2. 统一移动元素
for (let j = i - 1; j >= left; j--) {
arr[j + 1] = arr[j];
}
arr[left] = current;
}
return arr;
}
关键点
- 比较次数减少:查找插入位置从 O(n) 降为 O(log n)
- 移动次数不变:元素移动仍是 O(n),总体时间复杂度仍为 O(n²)
- 稳定排序:相等元素使用
arr[mid] > current保证稳定性 - 适用场景:比较操作代价高时(如字符串比较)效果更明显
- 空间复杂度:O(1),原地排序
目录