博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

list::sort() 源码解释

Posted on 2011-05-10 15:18  李大嘴  阅读(3453)  评论(0编辑  收藏  举报
1 template <class T, class Alloc>
2
3  void list<T, Alloc>::sort() {
4
5 if (node->next == node || link_type(node->next)->next == node) return;
6
7 list<T, Alloc> carry;
8
9 list<T, Alloc> counter[64];
10
11 int fill = 0;
12
13 while (!empty()) {
14
15 carry.splice(carry.begin(), *this, begin());
16
17 int i = 0;
18
19 while(i < fill && !counter[i].empty()) {
20
21 counter[i].merge(carry);
22
23 carry.swap(counter[i++]);
24
25 }
26
27 carry.swap(counter[i]);
28
29 if (i == fill) ++fill;
30
31 }
32
33 for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1]);
34
35 swap(counter[fill-1]);
36
37 }

这是sgi stl的 list.sort源码

侯捷的STL源码剖析 有对很多源码进行了解释,但这个函数切只是翻译了下原注释几乎没有对核心进行解释,而且貌似他的解释还是错误的。他说此函数采用quick sort。但没有发现快速排序的特征,没有找基准的位置,没有划分为左右,也不是内部排序..等。

第6章的算法的泛化过程find例子 貌似也错了。find函数返回比较不应该用数组的end()来比较,而应当用find函数的第2个参数做比较!


/* Written     By     MaiK */

    STL中的list被实现为环状的双向链表,设置一个“哨兵”node作为end( )。鉴于list的内存分配模型,list不能使用通用的标准sort算法,而是实现自身的sort,但是list有自己的成员函数sort()可供其自身调用,其实际模型是基于合并排序的。普通的mergesort直接将待排序的序列一分为二,然后各自递归调用mergesort,再使用Merge算法用O(n)的时间将已排完序的两个子序列归并,从而总时间效率为n*lg(n)。(mergesort是很好的排序算法,绝对时间很小,n*lg(n)之前的系数也很小,但是在内存中的排序算法中并不常见,我想可能主要还是因为耗空间太多,也是O(n)).

    不过list_sort所使用的mergesort形式上大不一样:将前两个元素归并,再将后两个元素归并,归并这两个小子序列成为4个元素的有序子序列;重复这一过程,得到8个元素的有序子序列,16个的,32个的。。。,直到全部处理完。主要调用了swap和merge函数,而这些又依赖于内部实现的transfer函数(其时间代价为O(1))。该mergesort算法时间代价亦为n*lg(n),计算起来比较复杂。list_sort中预留了 64个temp_list,所以最多可以处理2^64-1个元素的序列,这应该足够了。

/* Written     By    Lamar */

    类似2进制,每一次进位都是相邻高位数值的一半,所以是类2进制地。例如8,低位4满之后会进4个到8的。