STL源码学习——Lists(链表)

来源:互联网 发布:php session cookie 编辑:程序博客网 时间:2024/06/04 01:19

STL源码学习——Lists(链表)

  今天突然想起来看看开源项目,找了找最后决定好好看看经典的STL喵~
  和STL里的代码比起来我突然觉得以前写的代码也太不规范了喵,估计很多ACMer都一样吧喵。

  先从简单的看、先挑了一发list的源码来看。总结如下:

    欢迎大家一起讨论喵~


  1 :list是用双向循环链表实现的,就是说 list.end()+1 == list.begin()
  2 :list中有一个关键结点,这个结点是 list.end()
  3 :在看了list中的erase函数后,发现这个函数没有对end()结点进行特殊处理,所以很遗憾list在erase(end)后就会出现一些意想不到的情况,比如以下代码会让list容器死循环喵~(虽然这个操作本来就是非法的)

复制代码
 1 int main() 2 { 3     list<int> ls; 4     ls.insert(ls.begin(), 0); 5     ls.insert(ls.begin(), 1); 6     ls.erase(ls.end()); 7     for(list<int>::iterator it=ls.begin(); it!=ls.end(); ++it) 8         printf("it -> %d\n", *it); 9     return 0;10 }
复制代码

  4 :erase(it)之后会返回应该在原先it位置的元素。同样erase(end)后返回值是不对的。(erase(end)后的返回值为begin喵~)

  5 :erase()函数并未检测传入参数是否是本身这个list的。所以如果你有两个list:L1、L2,你这样写也是对的喵~

L1.erase( L2.begin() );

  


  6 :list里居然自己实现了sort算法喵,而且时间复杂度O(n*lg n)、空间复杂度O(1)。以前并没有仔细想list的排序问题,一直很单纯的以为list排序很慢。今天看了一发源码才知道原来链表排序也可以这么优越喵~

  这里,《STL源码剖析》中采用的如下解释:解释为快速排序。


  大致说一下算法喵:这里采用的是归并排序算法的思想。
  先将0、1两元素排序,再将2、3两元素排序。
  接下来就是排序前4个元素,
  然后,同上前8、16、32 ... 个元素
  具体实现用了64个桶,每个依编号存放2^n个元素。然后就像二进制加法一样,每次对个位进行加一操作,通过进位过程可将排好序的桶进行合并了喵。
由于链表的特殊性,无须另开空间存放元素,只需将原来的结点移动位置即可喵~

list::sort()
复制代码
 1     void sort(_StrictWeakOrdering __comp) 2     { 3         // Do nothing if the list has length 0 or 1. 4         if (_M_node._M_data->_M_next != _M_node._M_data && 5                 (_M_node._M_data->_M_next)->_M_next != _M_node._M_data) 6         { 7             list<_Tp, _Alloc> __carry; 8             list<_Tp, _Alloc> __counter[64]; 9             int __fill = 0;10             while (!empty())11             {12                 __carry.splice(__carry.begin(), *this, begin());   //个位加一13                 int __i = 0;14                 while(__i < __fill && !__counter[__i].empty())15                 {16                     __counter[__i].merge(__carry, __comp);17                     __carry.swap(__counter[__i++]);18                 }19                 __carry.swap(__counter[__i]);20                 if (__i == __fill) ++__fill;21             }22 23             for (int __i = 1; __i < __fill; ++__i)24                 __counter[__i].merge(__counter[__i-1], __comp);25             swap(__counter[__fill-1]);26         }27     }
复制代码

  7 :关于resize()我以前一直以为list会存放一个size_val,结果它木有存,resize的复杂度是线性的。所以如果size比较大的话,还是少resize()为好喵。

当然现在也可以理解为什么没有存放size_val了喵,因为存在这个时间复杂度为O(1)的insert函数。

void insert( iterator pos, input_iterator start, input_iterator end );

  

  8 :“operator=” list里这个函数比我想像的要聪明喵。
  我以为它会先erase(begin(), end()),然后再一个一个的加进去。
  结果它是先将就目标list中已创建的结点先用着,然后采用”多退少补“的原则喵~



0 0
原创粉丝点击