STL Containers & Iterators part2(Chapter 4 of Thinking in C++ Vol 2)

The vector is intentionally made to look like a souped-up array, since it has array-style indexing but also can expand dynamically. vector is so fundamentally useful that it was introduced in a very primitive way early in this book, and used quite regularly in previous examples. This section will give a more in-depth look at vector.
To achieve maximally-fast indexing and iteration, the vector maintains its storage as a single contiguous array of objects. This is a critical point to observe in understanding the behavior of vector. It means that indexing and iteration are lighting-fast, being basically the same as indexing and iterating over an array of objects. But it also means that inserting an object anywhere but at the end (that is, appending) is not really an acceptable operation for a vector. It also means that when a vector runs out of pre-allocated storage, in order to maintain its contiguous array it must allocate a whole new (larger) chunk of storage elsewhere and copy the objects to the new storage. This has a number of unpleasant side effects.
The deque (double-ended-queue, pronounced “deck”) is the basic sequence container optimized for adding and removing elements from either end. It also allows for reasonably fast random access – it has an operator[ ] like vector. However, it does not have vector’s constraint of keeping everything in a single sequential block of memory. Instead, deque uses multiple blocks of sequential storage (keeping track of all the blocks and their order in a mapping structure). For this reason the overhead for a deque to add or remove elements at either end is very low. In addition, it never needs to copy and destroy contained objects during a new storage allocation (like vector does) so it is far more efficient than vector if you are adding an unknown quantity of objects. This means that vector is the best choice only if you
have a pretty good idea of how many objects you need. In addition, many of the programs shown earlier in this book that use vector and push_back( ) might be more efficient with a deque. The interface to deque is only slightly different from a vector (deque has a push_front( ) and pop_front( ) while vector does not, for example) so converting code from using vector to using deque is almost trivial. 
A list is implemented as a doubly-linked list and is thus designed for rapid insertion and removal of elements in the middle of the sequence (whereas for vector and deque this is a much more costly operation). A list is so slow when randomly accessing elements that it does not have an operator[ ]. It’s best used when you’re traversing a sequence, in order, from beginning to end (or end to beginning) rather than choosing elements randomly from the middle. Even then the traversal is significantly slower than either a vector or a deque, but if
you aren’t doing a lot of traversals that won’t be your bottleneck.
Another thing to be aware of with a list is the memory overhead of each link, which requires a forward and backward pointer on top of the storage for the actual object. Thus a list is a better choice when you have larger objects that you’ll be inserting and removing from the middle of the list. It’s better not to use a list if you think you might be traversing it a lot, looking for objects, since the amount of time it takes to get from the beginning of the list – which is the only place you can start unless you’ve already got an iterator to somewhere you know is closer to your destination – to the object of interest is proportional to the number of objects between the beginning and that object.
The objects in a list never move after they are created; “moving” a list element means changing the links, but never copying or assigning the actual objects. This means that a held iterator never moves when you add new things to a list as it was demonstrated to do in vector. 
ExpandedBlockStart.gif Performance
  1  #include  < vector >
  2  #include  < queue >
  3  #include  < list >
  4  #include  < iostream >
  5  #include  < string >
  6  #include  < typeinfo >
  7  #include  < ctime >
  8  #include  < cstdlib >
  9  using   namespace  std;
 10 
 11  class  FixedSize 
 12  {
 13       int  x[ 20 ];
 14       //  Automatic generation of default constructor,
 15       //  copy-constructor and operator=
 16  } fs;
 17 
 18  template < class  Cont >
 19  struct  InsertBack 
 20  {
 21       void   operator ()(Cont &  c,  long  count) 
 22      {
 23           for ( long  i  =   0 ; i  <  count; i ++ )
 24              c.push_back(fs);    
 25      }
 26 
 27       char *  testName() {  return   " InsertBack " ; }
 28  };
 29 
 30  template < class  Cont >
 31  struct  InsertFront 
 32  {
 33       void   operator ()(Cont &  c,  long  count) 
 34      {
 35           long  cnt  =  count  *   10 ;
 36           for ( long  i  =   0 ; i  <  cnt; i ++ )
 37              c.push_front(fs);
 38      }
 39 
 40       char *  testName() {  return   " InsertFront " ; }
 41  };
 42 
 43  template < class  Cont >
 44  struct  InsertMiddle 
 45  {
 46       void   operator ()(Cont &  c,  long  count) 
 47      {
 48          typename Cont::iterator it;
 49           long  cnt  =  count  /   10 ;
 50           for ( long  i  =   0 ; i  <  cnt; i ++
 51          {
 52               //  Must get the iterator every time to keep
 53               //  from causing an access violation with
 54               //  vector. Increment it to put it in the
 55               //  middle of the container:
 56              it  =  c.begin();
 57              it ++ ;
 58              c.insert(it, fs);
 59          }
 60      }
 61 
 62       char *  testName() {  return   " InsertMiddle " ; }
 63  };
 64 
 65  template < class  Cont >
 66  struct  RandomAccess 
 67  //  Not for list
 68       void   operator ()(Cont &  c,  long  count) 
 69      {
 70           int  sz  =  c.size();
 71           long  cnt  =  count  *   100 ;
 72           for ( long  i  =   0 ; i  <  cnt; i ++ )
 73              c[rand()  %  sz];
 74      }
 75       char *  testName() {  return   " RandomAccess " ; }
 76  };
 77 
 78  template < class  Cont >
 79  struct  Traversal 
 80  {
 81       void   operator ()(Cont &  c,  long  count) 
 82      {
 83           long  cnt  =  count  /   100 ;
 84           for ( long  i  =   0 ; i  <  cnt; i ++
 85          {
 86              typename Cont::iterator it  =  c.begin(),
 87              end  =  c.end();
 88               while (it  !=  end) it ++ ;
 89          }
 90      }
 91 
 92       char *  testName() {  return   " Traversal " ; }
 93  };
 94 
 95  template < class  Cont >
 96  struct  Swap 
 97  {
 98       void   operator ()(Cont &  c,  long  count) 
 99      {
100           int  middle  =  c.size()  /   2 ;
101          typename Cont::iterator it  =  c.begin(),
102          mid  =  c.begin();
103          it ++ //  Put it in the middle
104           for ( int  x  =   0 ; x  <  middle  +   1 ; x ++ )
105              mid ++ ;
106           long  cnt  =  count  *   10 ;
107           for ( long  i  =   0 ; i  <  cnt; i ++ )
108              swap( * it,  * mid);
109      }
110 
111       char *  testName() {  return   " Swap " ; }
112  };
113 
114  template < class  Cont >
115  struct  RemoveMiddle 
116  {
117       void   operator ()(Cont &  c,  long  count) 
118      {
119           long  cnt  =  count  /   10 ;
120           if (cnt  >  c.size()) 
121          {
122              cout  <<   " RemoveMiddle: not enough elements "   <<  endl;
123               return ;
124          }
125           for ( long  i  =   0 ; i  <  cnt; i ++
126          {
127              typename Cont::iterator it  =  c.begin();
128              it ++ ;
129              c.erase(it);
130          }
131      }
132 
133       char *  testName() {  return   " RemoveMiddle " ; }
134  };
135 
136  template < class  Cont >
137  struct  RemoveBack 
138  {
139       void   operator ()(Cont &  c,  long  count) 
140      {
141           long  cnt  =  count  *   10 ;
142           if (cnt  >  c.size()) 
143          {
144              cout  <<   " RemoveBack: not enough elements "   <<  endl;
145               return ;
146          }
147           for ( long  i  =   0 ; i  <  cnt; i ++ )
148              c.pop_back();
149      }
150 
151       char *  testName() {  return   " RemoveBack " ; }
152  };
153 
154  template < class  Op,  class  Container >
155  void  measureTime(Op f, Container &  c,  long  count)
156  {
157       string  id(typeid(f).name());
158       bool  Deque  =  id.find( " deque " !=   string ::npos;
159       bool  List  =  id.find( " list " !=   string ::npos;
160       bool  Vector  =  id.find( " vector " != string ::npos;
161       string  cont  =  Deque  ?   " deque "  : List  ?   " list " : Vector ?   " vector "  :  " unknown " ;
162      cout  <<  f.testName()  <<   "  for  "   <<  cont  <<   " " ;
163       //  Standard C library CPU ticks:
164      clock_t ticks  =  clock();
165      f(c, count);  //  Run the test
166      ticks  =  clock()  -  ticks;
167      cout  <<  ticks  <<  endl;
168  }
169 
170  typedef deque < FixedSize >  DF;
171  typedef list < FixedSize >  LF;
172  typedef vector < FixedSize >  VF;
173 
174  int  main( int  argc,  char *  argv[]) 
175  {
176      srand(time( 0 ));
177       long  count  =   1000 ;
178       if (argc  >=   2
179          count  =  atoi(argv[ 1 ]);
180      DF deq;
181      LF lst;
182      VF vec, vecres;
183      vecres.reserve(count);  //  Preallocate storage
184      measureTime(InsertBack < VF > (), vec, count);
185      measureTime(InsertBack < VF > (), vecres, count);
186      measureTime(InsertBack < DF > (), deq, count);
187      measureTime(InsertBack < LF > (), lst, count);
188       //  Can't push_front() with a vector:
189       // ! measureTime(InsertFront<VF>(), vec, count);
190      measureTime(InsertFront < DF > (), deq, count);
191      measureTime(InsertFront < LF > (), lst, count);
192      measureTime(InsertMiddle < VF > (), vec, count);
193      measureTime(InsertMiddle < DF > (), deq, count);
194      measureTime(InsertMiddle < LF > (), lst, count);
195      measureTime(RandomAccess < VF > (), vec, count);
196      measureTime(RandomAccess < DF > (), deq, count);
197       //  Can't operator[] with a list:
198       // ! measureTime(RandomAccess<LF>(), lst, count);
199      measureTime(Traversal < VF > (), vec, count);
200      measureTime(Traversal < DF > (), deq, count);
201      measureTime(Traversal < LF > (), lst, count);
202      measureTime(Swap < VF > (), vec, count);
203      measureTime(Swap < DF > (), deq, count);
204      measureTime(Swap < LF > (), lst, count);
205      measureTime(RemoveMiddle < VF > (), vec, count);
206      measureTime(RemoveMiddle < DF > (), deq, count);
207      measureTime(RemoveMiddle < LF > (), lst, count);
208      vec.resize(vec.size()  *   10 );  //  Make it bigger
209      measureTime(RemoveBack < VF > (), vec, count);
210      measureTime(RemoveBack < DF > (), deq, count);
211      measureTime(RemoveBack < LF > (), lst, count);
212 
213      cin. get ();
214  /// :~

 

 

转载于:https://www.cnblogs.com/zhtf2014/archive/2011/02/22/1961506.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值