stl中list的sort算法实现

STL中有一个std::sort算法,但它是不支持std::list的,因为list不提供RandomIterator的支持,但list自己提供了sort算法,把list的元素按从小到大的方式来排序,代码长度到不长,但真是难以读懂,后来扣持了一下午终于搞明白了,贴个总结上来。

list::sort的代码如下(sgi stl):

[cpp]  view plain  copy
  1. template <class _Tp, class _Alloc>  
  2. void list<_Tp, _Alloc>::sort()  
  3. {  
  4.     // Do nothing if the list has length 0 or 1.  
  5.     if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {  
  6.         list<_Tp, _Alloc> __carry;  
  7.         list<_Tp, _Alloc> __counter[64];  
  8.         int __fill = 0;  
  9.         while (!empty()) {  
  10.             __carry.splice(__carry.begin(), *this, begin());  
  11.             int __i = 0;  
  12.             while(__i < __fill && !__counter[__i].empty()) {  
  13.                 __counter[__i].merge(__carry);  
  14.                 __carry.swap(__counter[__i++]);  
  15.             }  
  16.             __carry.swap(__counter[__i]);        
  17.             if (__i == __fill) ++__fill;  
  18.         }   
  19.         for (int __i = 1; __i < __fill; ++__i)  
  20.             __counter[__i].merge(__counter[__i-1]);  
  21.         swap(__counter[__fill-1]);  
  22.     }  
  23. }  

行数的确不多,但还真麻烦,我先说一下他是怎么实现的,但具体为什么这么做,我不知道。

比如我们的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

 

 脑算流程总算完了,但代码还是很难理解,先看一个几个相关的函数吧

1.splice:把当前列表的__i位置元素删除,保存在__position里

[cpp]  void list::splice(iterator __position, list&, iterator __i)  
[cpp]  view plain  copy
  1. void list::splice(iterator __position, list&, iterator __i)  

 

2.merge:把参数list的元素合并到当前list,参数list的内容会清空的

[c-sharp]  void list<_Tp, _Alloc>::merge(list<_Tp, _Alloc>& __x)

/* 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的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C++ STL(Standard Template Library)是一种功能强大的库,提供了一套丰富的数据结构和算法实现。在余文溪的《C++ STL数据结构与算法实现》这本PDF书,详细介绍了STL的各种数据结构和算法实现。 首先,STL提供了几种基本的数据结构,例如vector(动态数组)、list(双向链表)、deque(双端队列)、set(集合)、map(映射)等。这些数据结构在STL都有相应的实现和操作函数,能够方便地进行插入、删除、查找等操作。 此外,STL还提供了一些算法,包括排序、查找、遍历等等。这些算法可以应用于STL的各种数据结构上,提供了一种高效且易用的方式来处理数据。例如,STL提供了排序算法sort,可以对vector、list等容器进行排序操作;还有查找算法find,可以在set、map等容器进行查找操作。 在《C++ STL数据结构与算法实现,余文溪详细阐述了STL实现原理和内部细节,帮助读者深入理解STL的工作原理。通过学习这本书,读者可以了解到STL的设计思想、使用方法和性能特点,从而能够更好地应用STL解决问题。 总而言之,STL提供了一套强大的数据结构和算法实现,通过余文溪的《C++ STL数据结构与算法实现》这本PDF书,读者可以深入了解STL的使用方法和内部原理,提升编程能力。 ### 回答2: C++ STL(Standard Template Library,标准模板库)是C++标准库的一部分,为我们提供了丰富的数据结构和算法实现。余文溪编写的《C++ STL 数据结构域算法实现》PDF是一本介绍STL的经典教材。 STL包含了很多常用的数据结构,例如向量(vector)、链表(list)、集合(set)和映射(map)等。这些数据结构都已经被封装好,通过STL可以方便地进行插入、删除、查找等操作。同时,STL还提供了强大的算法库,例如排序、查找、拷贝和逆序等。使用STL的数据结构和算法,可以极大地提高我们的编程效率。 《C++ STL 数据结构域算法实现》是一本很好的学习STL的教材。其,余文溪详细地介绍了STL的各种数据结构和算法,通过代码示例和讲解,深入浅出地帮助读者理解STL的使用方法。这本教材适合初学者和有一定基础的读者阅读,对于了解STL的基本概念和使用方法非常有帮助。 在读完《C++ STL 数据结构域算法实现》后,读者将能够熟练使用STL提供的数据结构和算法,加快自己的编程效率。同时,通过掌握STL的使用,读者也能更好地理解C++标准库的设计思想和使用方法,提升自己的编程水平。 总之,《C++ STL 数据结构域算法实现》是值得一读的一本STL教材,能够帮助我们更好地学习和应用STL,提高我们的编程效率和水平。 ### 回答3: STL(Standard Template Library)是C++的标准库之一,提供了丰富的数据结构和算法实现。而余文溪编写的《C++ STL数据结构与算法实现》这本PDF书籍主要介绍了STL的使用方法和内部实现原理。 该书首先介绍了STL的基本概念和使用方法,包括迭代器、容器、算法等方面的内容。通过对各种容器(如vector、list、set、map等)和算法(如排序、查找、合并等)的讲解,读者可以了解到STL的强大功能和高效性。 此外,余文溪在书也深入探讨了STL的内部实现原理。他通过剖析STL的源代码,详细解释了其的数据结构和算法实现细节。这对于希望深入理解STL底层机制的读者来说,是非常有价值的。 《C++ STL数据结构与算法实现》这本书的另一个特点是提供了大量的示例代码和实战练习。通过实际编写代码和完成练习,读者可以巩固所学知识,并提升自己的编程能力。 总之,余文溪的这本PDF书籍对于想要掌握STL的使用方法和底层实现原理的C++程序员来说,是一本非常实用的工具书。无论是初学者还是有一定经验的开发者,都可以从获得很多有价值的知识和技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值