標准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
