zoukankan      html  css  js  c++  java
  • 【转】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

  • 相关阅读:
    WordPress网站绑定多个域名的方法
    htpasswd 命令使用
    在Windows下用OpenSSL生成证书步骤
    WCF中关于List和数据的转换问题
    NET2.0的配置文件
    C# Attribute
    c#自定义属性
    VS2005中读写配置文件(方法二)
    c#的反射
    Asp.NET 操作配置文件 Steven Pei 博客园
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/13604620.html
Copyright © 2011-2022 走看看