• (转)SGI STL中list的sort函数实现


    sgi stl中list的sort()函数内容如下:

    1. // list 不能使用STL 算法 sort(),必须使用自己的 sort() member function,  
    2. // 因为STL算法sort() 只接受RamdonAccessIterator.  
    3. // 本函式采用 quick sort.  
    4. template <class T, class Alloc>  
    5. void list<T, Alloc>::sort() {  
    6. // 以下判断,如果是空白串行,或仅有一个元素,就不做任何动作。  
    7. if (node->next == node || link_type(node->next)->next == node) return;  
    8.   
    9. // 一些新的 lists,做为中介数据存放区  
    10. list<T, Alloc> carry;  
    11. list<T, Alloc> counter[64];  
    12. int fill = 0;  
    13. while (!empty()) {  
    14. carry.splice(carry.begin(), *this, begin()); //取出list中的一个数据,存入carry  
    15. int i = 0;  
    16. while(i < fill && !counter[i].empty()) {  
    17. counter[i].merge(carry); //将carry中的数据,和 counter[i]链中原有数据合并  
    18. carry.swap(counter[i++]); //交换carry 和counter[i] 数据  
    19. }  
    20. carry.swap(counter[i]);   
    21. if (i == fill) ++fill;  
    22. }  
    23.   
    24. for (int i = 1; i < fill; ++i) // sort之后,善后处理,把数据统一起来  
    25. counter[i].merge(counter[i-1]);  
    26. swap(counter[fill-1]);  
    27. }  


    详细道来:
    fill ------> 2^fill 表示现在能处理的数据的最大数目
    counter[ fill ]---> 将处理完的2^fill个数据存入 counter[ fill ]中
    carry---> 就像一个临时中转站, 在处理的数据不足 2 ^ fil l时,在counter[ i ] ( 0=<i<fill)之间移动数据(改变指针)

    步骤如下:
    1) 读入一个数据(carry.splice),通过 carry 将数据存入 counter[0] 中;
    随后处理下一个数据, carry 保存数据
    a. counter[0].merge(carry) , 此时 counter[0] 容纳的数据个数 > 2^0
    b. 将counter[0]链中的数据,通过carry,转移到counter[1]链,.... 直至处理的数据个数达到 2 ^ fill

    2) fill++ , 重复 1) 至处理完所有的数据。


    非递归的快速排序实现方式,很巧妙!!!
    counter 数组为64 --- 所以此算法,一次最多能处理 2 ^ 64 -2 个数据

    比如我们的list里有如下几个需要排序的元素:21,45,1,30,52,3,58,47,22,59,0,58。

    排序的时候怎么做,我们先定义若干中转list在上述代码中定义了64个元素的数组

    list<_Tp, _Alloc> __counter[64]; 其中里边存什么呢?他们都是用来中转用的

    __counter[0]里存放2(0+1)次方个元素
    __counter[1]里存放2(1+1)次方个元素
    __counter[2]里存放2(2+1)次方个元素
    __counter[3]里存放2(3+1)次方个元素,依次类推

     

     

    那又是怎么个存放方法呢?一个指导原则就是当第i个元素即__counter[i]的内容个数等于2(i+1)次方时,就要把__counter[i]的数据转移给__count[i+1]。

    具体过程如下:

    取出第1个数21,放到__counter[0]里,这时__counter[0]里有一个元素,小于2,继续

    __counter[0]: 21

    __counter[1]: NULL

    取出第2个数45,放到__counter[0]里(不是简单的放,而是排序放,类似两个list做merge),这时__counter[0]里有2个元素了,需要把这两个元素转移到__counter[1].

    __counter[0]: NULL

    __counter[1]: 21,45

    取出第3个数1,放到__counter[0]里,__count[0]与__count[1]都小于规定个数

    __counter[0]: 1

    __counter[1]: 21,45

    取出第4个数30,放到__counter[0]里,这时__counter[0]的个数等于2了,需要转移到__counter[1]里

    __counter[0]: NULL

    __counter[1]: 1,21,30,45

    但这时__counter[1]里的个数又等于4了,所有需要把__counter[1]的值转移到__counter[2]里,

    __counter[0]: NULL

    __counter[1]: NULL

    __counter[2]: 1,21,30,45

    然后取出52,放入__counter[0]

    __counter[0]: 52

    __counter[1]: NULL

    __counter[2]: 1,21,30,45

    然后取出3,放入__counter[0]

    __counter[0]: 3,52

    __counter[1]: NULL

    __counter[2]: 1,21,30,45

    这时候需要转移

    __counter[0]: NULL

    __counter[1]: 3,52

    __counter[2]: 1,21,30,45

    然后取58

    __counter[0]: 58

    __counter[1]: 3,52

    __counter[2]: 1,21,30,45

    然后取47

    __counter[0]: 47,58

    __counter[1]: 3,52

    __counter[2]: 1,21,30,45

    需要转移

    __counter[0]: NULL

    __counter[1]: 3,47,52,58

    __counter[2]: 1,21,30,45

    还需要转移

    __counter[0]: NULL

    __counter[1]: NULL

    __counter[2]: 1,3,21,30,47,45,52,58

    还需要转移

    __counter[0]: NULL

    __counter[1]: NULL

    __counter[2]: NULL

    __counter[3]: 1,3,21,30,47,45,52,58

    然后再取59

    __counter[0]: 59

    __counter[1]: NULL

    __counter[2]: NULL

    __counter[3]: 1,3,21,30,47,45,52,58

    然后取0

    __counter[0]: 0,59

    __counter[1]: NULL

    __counter[2]: NULL

    __counter[3]: 1,3,21,30,47,45,52,58

    需要转移

    __counter[0]: NULL

    __counter[1]: 0,59

    __counter[2]: NULL

    __counter[3]: 1,3,21,30,47,45,52,58

    最后取58

    __counter[0]: 58

    __counter[1]: 0,59

    __counter[2]: NULL

    __counter[3]: 1,3,21,30,47,45,52,58

     

    转自:http://blog.csdn.net/zhizichina/article/details/7538974

  • 相关阅读:
    display: flex
    TTStand --Variant的应用
    跨域
    HTTP 响应状态代码
    SQL Server 2017 Developer and Express
    WPF 中 通过点击ListBox中的元素自动选中一整项
    C#计算屏幕的物理宽和高
    C#常用设计模式
    EntityFrameworkCore之工作单元的封装
    内存包装类 Memory 和 Span 相关类型
  • 原文地址:https://www.cnblogs.com/yysblog/p/2501283.html
Copyright © 2020-2023  润新知