STL容器之size()函数的实现

原创 2016年05月30日 20:31:26

vector   O(1)

list        O(n)

deque


以下转自:http://www.07net01.com/2014/09/79439.html

使用C++进行开发,一部分人可能喜欢使用STL,即C++标准模板库。对容器使用可能最多,算法相对比较少。我在开发中基本上也就是使用容器:vector, list, deque, map, hashtable, hash_map。
         在实际情况不是特别要求自己需要实现特殊的数据结构的时候,一般采用STL容器,是又快又好又安全的做法。
         孙子兵法曰:“知己知彼,百战不殆”。
         我们一般人写程序,不可避免要使用别人开发的库来搭积木。其实也讲究这个“知己知彼”:
         知己—-对自己程序要实现的业务逻辑分析清楚,时间上、空间上的复杂度等;
         知彼—-对我们所使用的库也要有一定的了解,了解的越清楚越好;当然我们可能不会去完全了解各个库,这要看个人的修养方向了。
         回到STL容器来说,一般容器都有size()成员函数的实现,我们很明白它返回的是容器里元素的个数,一般可能都认为这个size()应该及其简单,时间复杂度应该是O(1)。实际情况是不是这样呢,我们简单分析下vector, list, deque(我下载的是SGI源代码)。
      先看vector:




以下是代码片段:
    class vector {
         public:
                  size_type size() const
                   { return size_type(end() – begin()); }
                  
                  iterator begin() { return _M_start; }

                  iterator end() { return _M_finish; }
                  
         protected:
              _Tp* _M_start;
              _Tp* _M_finish;
              _Tp* _M_end_of_storage;
      };

      可见,vector的size()实现在时间复杂度上确实是常量级的,很简单很快,就如我们想像中一样。注意它没有一个_size。

      再看list:




以下是代码片段:
      class list{
         public:
            size_type size() const {
                size_type __result = 0;
                distance(begin(), end(), __result);
                return __result;
              }
      };

      注意了,尽然不是我们想象的。既不同于vector实现,也没有一个_size, 而是调用的一个全局函数:
      头文件stl_iterator_base.h:




以下是代码片段:
      template <class _InputIterator, class _Distance>
      inline void distance(_InputIterator __first, _InputIterator __last, _Distance& __n)
      {
           __STL_REQUIRES(_InputIterator, _InputIterator);
           __distance(__first, __last, __n, iterator_category(__first));
      }

      template <class _InputIterator, class _Distance>
      inline void __distance(_InputIterator __first, _InputIterator __last, _Distance& __n, input_iterator_tag)
      {
           while (__first != __last) { ++__first; ++__n; }
      }

      大家看到了吧,它竟然使用迭代器遍历了整个链表,那么size()在时间复杂度上就不再是我们想象中的常量级,而是O(n)。为什么这样呢,这要对iterator和traits有所了解,才明白这么做的必要性。
      所以,如果你的list里数据很多,而你每次操作前还要调用size()来看看是否超过你的最大数目,那执行速度比你想象中要慢很多。所以处理这种情况,如果你必须每次要看看它的元素数目,把list包装一下,自己维护一个_size算了,也浪费不了多少内存,4字节嘛。

     最后看看deque:       




以下是代码片段:
       class deque {
          public:
               size_type size() const { return _M_finish – _M_start; }
         protected:
              iterator _M_start;
              iterator _M_finish;
      };

      不错,看起来和vector一样,其实不然。
      别忘了c++语法有一个重要概念:运算符重载。




以下是代码片段:
      struct _Deque_iterator {
            typedef _Deque_iterator<_Tp, _Tp&, _Tp*>             iterator;
            typedef ptrdiff_t difference_type;
            typedef _Deque_iterator _Self;

            difference_type operator-(const _Self& __x) const {
                return difference_type(_S_buffer_size()) * (_M_node – __x._M_node – 1) +
                     (_M_cur – _M_first) + (__x._M_last – __x._M_cur);
             }
       };

      为什么这么复杂了?这要怪deque采用map作为主控,使用分段连续线性空间的设计。怎么说都比list那个实现快。
       可以说STL的代码风格是让人难受的,当我们无聊而心情又好的时候,读读侯捷的《STL源码剖析》吧,分析对比一下,也有一些乐趣。
版权声明:本文为博主原创文章,未经博主允许不得转载。

STL学习笔记— —容器forward_list

简介在头文件 中定义namespace std { template class forward_forward_list; }单向列表是一个容器,支持在其任何地方快速插入和删除元素,不...
  • lyh03601
  • lyh03601
  • 2016年04月07日 21:43
  • 3155

坑爹的stl list 的size()成员函数

刚做hihocoder #1086 Browser Caching的题,一开始的做法是stl unorderd_map+list,满心以为一次就AC,结果……TLE了。O(N)也能TLE!!(╯‵□′...
  • lyingson
  • lyingson
  • 2015年09月15日 14:17
  • 1246

C++ STL之 vector的capacity和size属性区别

vector中这两个属性很容易弄混淆。 size是当前vector内变量真实占用的大小。 capacity是预留的空间大小。...
  • u013575812
  • u013575812
  • 2016年04月17日 00:07
  • 9525

关于STL容器的线程安全特性

标准C++的世界是相当保守和精简的。在这个纯洁的世界,所有可执行文件都是静态链接的。不存在内存映射文件和共享内存。没有窗口系统,没有网络,没有数据库,没有进程。在这种情况下,当发现标准没有提到任何关于...
  • gaokewoo
  • gaokewoo
  • 2014年04月26日 21:51
  • 875

STL容器的size()函数的一个容易忽略的点

STL容器的size()函数会返回容器里面的元素个数,它的类型是size_t,即无符号整型。而我之前没有留意这个,以为是整型,然后在一份代码中写了如下代码,找bug找了很久。。。 for(int i...
  • u014088857
  • u014088857
  • 2016年02月18日 11:29
  • 644

C++容器之forward_list

简介          Forward_list是一种能在常数时间内在任何位置插入和删除的顺序容器。Forward_list是单向链表。          Forward_list和list的区别...
  • tj807126663
  • tj807126663
  • 2014年06月03日 20:53
  • 770

Chapter 11.顺序容器forward_list[c++11]

前向链表简介 前向链表是用单链表实现的,可在常量时间内在链表中做插入或删除操作 list比之forward_list,双向链表要消耗额外的空间存储每个元素和在插入和删除元素时一个轻微的更高...
  • vv_VV_vv
  • vv_VV_vv
  • 2012年09月18日 00:09
  • 5300

C++ STL容器时间复杂度下的最佳选择

STL在C++11中还算是火热,想必大家早有耳闻,对于泛型编程而言,或者数据结构而言,STL都显得尤为重要。今天让我们来了解一下,根据时间复杂度这个条件,挑选最适合自己程序的STL。...
  • CSND_Ayo
  • CSND_Ayo
  • 2017年06月21日 16:24
  • 1411

带你深入理解STL之List容器

上一篇博客中介绍的vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,很好的支持了随机存取,但由于是连续空间,所以在中间进行插入、删除等操作时都造成了内存块的拷贝和移动,另外在内存空间...
  • terence1212
  • terence1212
  • 2016年08月24日 17:29
  • 2721

C++11中std::forward_list单向链表的使用

C++11中std::forward_list单向链表的使用
  • fengbingchun
  • fengbingchun
  • 2017年06月04日 12:33
  • 973
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:STL容器之size()函数的实现
举报原因:
原因补充:

(最多只允许输入30个字)