c++STL系列:常见问题

为什么set/map底层用红黑树而不用AVL树?

红黑树与AVL比较:

  1. AVL是严格平衡的,频繁的插入和删除,会引起频繁的rebalance,导致效率降低;红黑树是弱平衡的,算是一种折中,插入最多旋转2次,删除最多旋转3次。

  2. 红黑树在查找、插入删除的复杂度都是O(logn),且性能稳定,所以STL里面很多结构包括map底层都是使用的红黑树。

STL的sort内部使用什么排序算法?

直接上源码

1
2
3
4
5
6
7
template <class _RanIt, class _Pr>
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last), using _Pred
_Adl_verify_range(_First, _Last);
const auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));
}

这是一个入口函数,先检查迭代器的区间是不是合法的,然后进入主要的排序函数,下面看排序函数是怎么工作的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template <class _RanIt, class _Pr>
_CONSTEXPR20 void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) {
// order [_First, _Last), using _Pred
for (;;) {
if (_Last - _First <= _ISORT_MAX) { // small
_Insertion_sort_unchecked(_First, _Last, _Pred);
return;
}

if (_Ideal <= 0) { // heap sort if too many divisions
_Make_heap_unchecked(_First, _Last, _Pred);
_Sort_heap_unchecked(_First, _Last, _Pred);
return;
}

// divide and conquer by quicksort
auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);

_Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions

if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
_Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
_First = _Mid.second;
} else { // loop on first half
_Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
_Last = _Mid.first;
}
}
}

这是一个递归函数,注释可以说是非常清晰了。

  1. 首先检查要排序的长度,如果长度小于_ISORT_MAX = 32,那么直接进行插入排序。主要的想法是
    在32这么一个量级上序列基本上已经有序,使用插入排序效率已经相对较高。
  2. 然后检查递归深度,没进行一次递归,就对_Ideal进行 _Ideal = (_Ideal >> 1) + (_Ideal >> 2)操作,
    主要的作用是防止快排递归深度过深导致爆栈。
  3. 如果深度可以接受,进行快排。