折半插入排序

折半插入排序是对直接插入排序的优化。假如我们需要尝试找到第 i 个元素插入的位置,直接插入排序是从右向左进行遍历一个个去找。瓶颈就出现在这里。

由于我们的插入排序是从左到右进行遍历的,所以当我们遍历到第 i 个元素的时候前 i - 1 个元素已经有序了,于是我们就可以用二分查找找到待插入的位置。进行插入。

由于我们只对找到插入位置进行了优化,并没有对元素后移进行优化,所以算法的时间复杂度并没有变化,还是 O(n2)

实现

以下是升序的实现:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

void insert_sort() {
    for (int i = 1; i < n; i++) {
        if (a[i - 1] <= a[i]) continue;
        int t = a[i];
        int l = 0, r = i - 1;
        // 找到比 a[i] 大的第一个数
        while (l < r) {
            int mid = l + r >> 1;
            if (a[mid] > t) r = mid;
            else l = mid + 1;
        }
        // 移位
        for (int j = i - 1; j >= l; j--) 
            a[j + 1] = a[j];
        // 插入
        a[l] = t;
    }
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++) cin >> a[i];
    
    insert_sort();
    for (int i = 0; i < n; i++) cout << a[i] << " ";
    return 0;
}