Introsort 是一种混合排序算法,结合了三种经典算法的优点:
算法 | 用于 | 特点 |
---|---|---|
快速排序 | 通常情况 | 平均时间复杂度 O(n log n) |
堆排序 | 当快速排序退化(递归过深)时 | 最坏时间复杂度 O(n log n) |
插入排序 | 小规模数组时(如长度 ≤ 16) | 常数开销小,快 |
排序逻辑如下:
if (size <= 16)
插入排序(Insertion Sort)
else if (递归深度 > 2 * log2(n))
堆排序(Heap Sort)
else
快速排序(Quick Sort)
快速排序用于大多数正常情况:
pivot = median of first, middle, last
partition the array into <pivot and ≥pivot
recursively sort left and right partitions
优化细节包括:
当数组区间大小较小(如 ≤16),std::sort
使用插入排序:
for i from 1 to n:
insert a[i] into sorted part a[0...i-1]
优点:
当快速排序的递归深度超过阈值,意味着遇到了极端情况(如重复元素、逆序),则使用堆排序保证 O(n log n):
std::make_heap(begin, end);
std::sort_heap(begin, end);
确保时间复杂度不会退化成 O(n²)。
属性 | Introsort(std::sort) |
---|---|
最好时间复杂度 | O(n log n) |
平均时间复杂度 | O(n log n) |
最坏时间复杂度 | O(n log n) |
空间复杂度 | O(log n) 递归栈 |
是否稳定排序 | ❌ 否 |
void introsort(first, last, depth_limit) {
while (last - first > threshold) {
if (depth_limit == 0) {
heapsort(first, last);
return;
}
pivot = median_of_three(first, middle, last);
cut = partition(first, last, pivot);
introsort(cut, last, depth_limit - 1);
last = cut;
}
insertionsort(first, last);
}
std::sort
处理几乎所有排序任务(比手写快排或冒泡强百倍)std::stable_sort
(基于 MergeSort,代价是 O(n) 空间)std::vector
+ std::iota
+ std::sort
实现间接排序下面是一个简化版的 Introsort(内省排序) 实现。这个示例支持任意类型的数据,通过比较函数进行排序,结合了:
完整代码:introsort.hpp
#pragma once
#include
#include
#include
#include
#include
template<typename RandomIt, typename Compare>
void insertionSort(RandomIt first, RandomIt last, Compare comp) {
for (auto i = first + 1; i < last; ++i) {
auto key = std::move(*i);
auto j = i;
while (j > first && comp(key, *(j - 1))) {
*j = std::move(*(j - 1));
--j;
}
*j = std::move(key);
}
}
template<typename RandomIt, typename Compare>
void heapSort(RandomIt first, RandomIt last, Compare comp) {
std::make_heap(first, last, comp);
std::sort_heap(first, last, comp);
}
template<typename RandomIt, typename Compare>
void introsortUtil(RandomIt first, RandomIt last, int depthLimit, Compare comp) {
const int INSERTION_SORT_THRESHOLD = 16;
while (std::distance(first, last) > INSERTION_SORT_THRESHOLD) {
if (depthLimit == 0) {
heapSort(first, last, comp);
return;
}
// Median-of-three
RandomIt mid = first + (last - first) / 2;
if (comp(*mid, *first)) std::iter_swap(first, mid);
if (comp(*(last - 1), *first)) std::iter_swap(first, last - 1);
if (comp(*(last - 1), *mid)) std::iter_swap(mid, last - 1);
auto pivot = *mid;
// Lomuto partition
RandomIt i = first;
RandomIt j = last - 1;
while (true) {
while (comp(*i, pivot)) ++i;
while (comp(pivot, *j)) --j;
if (i >= j) break;
std::iter_swap(i, j);
++i;
--j;
}
introsortUtil(j + 1, last, depthLimit - 1, comp);
last = j + 1;
}
insertionSort(first, last, comp);
}
template<typename RandomIt, typename Compare>
void introsort(RandomIt first, RandomIt last, Compare comp) {
int depthLimit = 2 * std::log2(std::distance(first, last));
introsortUtil(first, last, depthLimit, comp);
}
// 默认比较函数重载
template<typename RandomIt>
void introsort(RandomIt first, RandomIt last) {
introsort(first, last, std::less<typename std::iterator_traits<RandomIt>::value_type>());
}
示例使用
#include
#include "introsort.hpp"
int main() {
std::vector<int> data = {42, 5, 17, 23, 99, 3, 8, 1, 57, 61};
std::cout << "Before sort: ";
for (auto x : data) std::cout << x << " ";
std::cout << std::endl;
introsort(data.begin(), data.end());
std::cout << "After sort: ";
for (auto x : data) std::cout << x << " ";
std::cout << std::endl;
return 0;
}
输出示例
Before sort: 42 5 17 23 99 3 8 1 57 61
After sort: 1 3 5 8 17 23 42 57 61 99
技术点 | 用法 |
---|---|
insertionSort |
小区间处理,避免快排递归开销 |
heapSort |
深度超限时兜底,保证 O(n log n) 性能 |
median-of-three |
快排选主元策略,避免最坏情况 |
std::iter_swap |
泛型交换,无需类型依赖 |
std::log2(n) |
控制递归深度阈值 |