【轉】std::list中size()方法的時間復雜度


  標准STL容器List(Linux GNU,sgi的實現),其size()函數的要遍歷所有list中的元素來獲得鏈表長度,來看看它的實現:

1 size_type size() const {
2     size_type __result = 0;
3     distance(begin(), end(), __result);
4     return __result;
5   }

  其通過調用distance()函數來計算元素個數,而distance方法的實現如下:

1 template <class _InputIterator, class _Distance>
2 inline void distance(_InputIterator __first, 
3                      _InputIterator __last, _Distance& __n)
4 {
5   __STL_REQUIRES(_InputIterator, _InputIterator);
6   __distance(__first, __last, __n, iterator_category(__first));
7 }

  又封了一層_distance(),看看它做了什么:

 1 template <class _InputIterator>
 2 inline typename iterator_traits<_InputIterator>::difference_type
 3 __distance(_InputIterator __first, _InputIterator __last, input_iterator_tag)
 4 {
 5   typename iterator_traits<_InputIterator>::difference_type __n = 0;
 6   while (__first != __last) {
 7     ++__first; ++__n;
 8   }
 9   return __n;
10 }

  原來是遍歷!為什么獲得鏈表長度必須要遍歷全部的鏈表元素才能獲得,而不是用一個變量來表示呢?sgi設計list的思路何以如此與眾不同呢

  原來作者是為了

splice(iterator position, list& x, iterator first, iterator last);

  方法所取的折衷。list 是鏈表結構,它的優勢就在於可以 O(1) 的時間復雜度任意插入甚至拼接 list 片段。list::splice() 是一個很強大的功能,它可在任意位置拼接兩個 list。如果我們在類內部以一個變量儲存 list 的長度,那么splice()之后新list的長度就需要遍歷待移動元素的first和last間的長度(然后把鏈表A保存的鏈表長度減去first和last之間的長度)。於是作者考慮將size()方法設計為O(N),就無需在splice()方法執行時做遍歷了。

1 void splice(iterator __position, list&, iterator __first, iterator __last) {
2     if (__first != __last) 
3       this->transfer(__position, __first, __last);
4   }

  再看看transfer干了些什么:

 1 void transfer(iterator __position, iterator __first, iterator __last) {
 2     if (__position != __last) {
 3       // Remove [first, last) from its old position.
 4       __last._M_node->_M_prev->_M_next     = __position._M_node;
 5       __first._M_node->_M_prev->_M_next    = __last._M_node;
 6       __position._M_node->_M_prev->_M_next = __first._M_node; 
 7  
 8       // Splice [first, last) into its new position.
 9       _List_node_base* __tmp      = __position._M_node->_M_prev;
10       __position._M_node->_M_prev = __last._M_node->_M_prev;
11       __last._M_node->_M_prev     = __first._M_node->_M_prev; 
12       __first._M_node->_M_prev    = __tmp;
13     }
14   }

  作者確實是考慮splice執行時,不用遍歷,而是僅僅移動幾個指針就可以了,因此犧牲了size的效率!

 

  轉自:https://blog.csdn.net/russell_tao/article/details/8572000


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM