好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

STL学习笔记vector

STL学习笔记vector

STL学习笔记--vector

vector 向量容器

    作为数组的一个泛化推广的 vector 容器,不仅可以进行数组一样的元素随机访问,还可以在容器的尾端插入新元素,是一个实现了 Random Access Container 和 Back Insertion Sequence 概念的模型
    vector 是一种简单、高效的容器。在尾端插入和删除元素,算法时间复杂度为 O(1) 常数阶,其他元素的插入删除为 O(n) 线型阶,其中 n 为 vector 容器的元素个数。 vector 具有自动的内存管理功能,对于元素的插入和删除,可动态调整所占用的内存空间。


创建 vector 对象
如下4个vector的构造函数,均可创建一个vector对象
1.    vector(const A& a = A())
    创建一个空的 vector 对象,A 是内存分配器,此参数可以省略,相当于一个 vector() 的调用。
例如,下面一行代码创建了一个 vector 对象 vInt
    vector<int> vInt;  

2.    vector(size_type n)
     创建一个具有 n 个元素的 vector 对象,每个 vector 元素具有它的类型下的默认值。此时, n 个 vector 元素的内存空间已被分配。
例如,下面一行代码创建了具有 10 个元素的 vector 对象 vDou,每个元素的默认值为 0.0
    vector<double> vDou(10);
    
3.    vector(size_type n, const T& value)
    创建一个具有 n 个元素的 vector 对象,每个元素具有初始值 value 。
例如,下面一行代码创建了一个具有 10 个元素的 vector 对象 vDou, 每个元素的初始值为 9.3
    vector<double> vDou(10, 9.3);
    
4.    vector(const vector&)
    通过拷贝一个 vector 对象的各个元素值,创建一个新的 vector 对象。
例如,下面使用 v1 对象 创建 v2 对象,此时,v2 对象的 5 个元素也具有字符值 "K"
    vector<char> v1(5,'K');
    vector<char> v2(v1);

这是第五种创建方法    
5.    vector(const InputInerator first, const InputIterator last, const A& a = A())
    InputIterator 为输入迭代器,通过拷贝迭代器区间 [first, last ) 的元素值,创建一个新的vector对象,内存分配器可省略。
例如,利用 int 数组 iArray 各元素值,创建了 vector 对象 v
    int iArray[] = {11, 13, 19, 23, 28};
    vector<int> v(iArray, iArray + 5);



初始化赋值
vector 提供的 push_back() 函数,常用来进行 vector 容器的初始化。 push_back() 函数在容器的尾端插入新元素。


元素的遍历访问
 vector 的元素可以采用数组,.at() 函数或者迭代器的方式进行遍历访问。

用数组方式访问 vector 元素

 1  #include <vector>
  2  #include <iostream>
  3   using   namespace   std;
   4   int   main()
   5   {
   6      vector< int >  vInt;
   7      vInt.push_back( 20  );
   8      vInt.push_back( 26  );
   9      vInt.push_back( 39  );
  10      
 11   //      cout << "VInt【2】 = " << vInt[2] <<endl;
  12   //      cout << "VInt【3】 = " << vInt[3] <<endl;
  13   //      cout << "VInt【4】 = " << vInt[4] <<endl << endl << endl;
  14   //     
 15   //      cout << "VInt【2】 = " << vInt.at(2) <<endl;    
  16   //      cout << "VInt【3】 = " << vInt.at(3) <<endl;
  17   //      cout << "VInt【4】 = " << vInt.at(4) <<endl; 
 18      
 19  
 20       for  ( int  i= 0 ; i<vInt.size(); i++ )
  21       {
  22           //   vInt[i] 为数组方式的访问。访问越界时,不产生异常
  23           //  cout << "VInt【" << i << "】 = " << vInt[i] <<endl;
  24          
 25           //   vInt.at(i) 为函数访问方式。当访问越界时,会抛出异常 
 26          cout <<  "  VInt【  "  << i <<  "  】 =   "  << vInt.at(i) << endl;
  27       }
  28  
 29  
 30       return   0  ;
  31  }

用迭代器访问 vector

 1   /*          解释:
   2       迭代器方式的访问就是使用 vector 容器提供的 iterator 类型,定义一个迭代器变量,例如:vector<int>::iterator i;
   3   然后,对迭代器进行 "++" 操作,将迭代器从一个元素位置移动到下一个元素位置,从而通过迭代器的 "*" 操作,将所有元素读出来。
   4       vector 提供了 begin(), end() 函数,用于获取首元素的迭代器和最后一个元素的下一个位置的迭代器
   5   */ 
  6  
  7  -------------------------------------------------------  用迭代器访问 vector 元素
   8  #include <vector>
  9  #include <iostream>
 10   using   namespace   std;
  11   int   main()
  12   {
  13      vector< int >  vInt;
  14      vInt.push_back( 20  );
  15      vInt.push_back( 26  );
  16      vInt.push_back( 39  );
  17  
 18       //   起始迭代器值  
 19      vector< int > ::iterator i;
  20       int   j;
  21       //   vInt不改变,可以在for 循环中,将i!=vInt.end()作为判断条件 
 22       for  (i=vInt.begin(), j= 0 ; i!=vInt.end(); i++, j++ )
  23       {
  24          cout <<  "  v[  "  << j <<  "  ] =   "  << *i <<  endl;
  25       }
  26  
 27       return   0  ;
  28  }

在任意位置插入 vector 元素

 1  --------------------------------  在任意位置插入 vector 元素
   2  #include <vector>
  3  #include <iostream>
  4   using   namespace   std;
   5   int   main()
   6   {
   7      vector< int >  vInt;
   8      vInt.push_back( 6  );
   9      vInt.push_back( 7  );
  10      vInt.push_back( 8  );
  11      vInt.push_back( 10  );
  12       //   在元素 10 的前面插入 9 
 13      vInt.insert(vInt.begin() +  3 ,  9  );
  14       //   插入 5 为首元素 
 15      vInt.insert(vInt.begin(),  5  );
  16       //   插入 11 为末元素 
 17      vInt.insert(vInt.end(),  11  );
  18  
 19       for  ( int  i= 0 ; i<vInt.size(); i++ )
  20       {
  21          cout <<  "  V[  "  << i <<  "  ]=  "  << vInt[i] <<  endl;
  22       }
  23  
 24       return   0  ;
  25  }

利用 erase 函数删除 vector 元素

 1  ----------------------------------------  利用 erase 函数删除 vector 元素
   2  #include <iostream>
  3  #include <vector>
  4   using   namespace   std;
   5   class   MyAnimal
   6   {
   7   public  :
   8       char *  m_name;
   9       int   m_age;
  10   public  :
  11      MyAnimal( char * name,  int   age)
  12       {
  13           this ->m_name =  name;
  14           this ->m_age =  age;
  15       }
  16      ~ MyAnimal(){}
  17  
 18   };
  19  
 20   int   main()
  21   {
  22      MyAnimal* pDog =  new  MyAnimal( "  dog  " ,  1  );
  23      MyAnimal* pMonkey =  new  MyAnimal( "  monkey  " ,  2  );
  24      MyAnimal* pChicken =  new  MyAnimal( "  chicken  " ,  3  );
  25      MyAnimal* pSnake =  new  MyAnimal( "  snake  " ,  4  );
  26  
 27       //   v 将存放各对象的地址 
 28      vector<MyAnimal*>  v;
  29       v.push_back(pDog);
  30       v.push_back(pMonkey);
  31       v.push_back(pChicken);
  32       v.push_back(pSnake);
  33  
 34       //   物理删除 pMonkey 所指的对象 
 35       delete pMonkey;
  36       //   删除第 2 个元素,即删除 vector 容器的元素 pMonkey 
 37      v.erase(v.begin()+ 1  );
  38      vector<MyAnimal*> ::iterator i, iend;
  39      iend =  v.end();
  40       for  (i=v.begin(); i!=iend; ++ i)
  41       {
  42          cout << (*i)->m_name <<  '   '  << (*i)->m_age << endl;
  43       }
  44       //   清除所有 vector 元素 
 45       v.clear();
  46      cout <<  "   执行 clear()   "  << endl <<  "  vector 元素已全部清除。  "  << endl;
  47  
 48       return   0  ;
  49  }

反向遍历 vector 的元素

 1  --------------------------------------------------  反向遍历 vector 的元素
   2  #include <vector>
  3  #include <iostream>
  4   using   namespace   std;
   5   int   main()
   6   {
   7      vector< int >  vInt;
   8      vInt.push_back( 1  );
   9      vInt.push_back( 3  );
  10      vInt.push_back( 5  );
  11      vInt.push_back( 7  );
  12      vInt.push_back( 9  );
  13       //   元素的反向遍历访问 
 14      vector< int > ::reverse_iterator ri,riend;
  15      riend =  vInt.rend();
  16       for  (ri=vInt.rbegin(); ri!=riend; ++ ri)
  17       {
  18          cout << *ri <<  endl;
  19       }
  20  
 21       return   0  ;
  22  }

两个 vector 容器元素的交换

 1  --------------------------------------------------  两个 vector 容器元素的交换
   2  #include <vector>
  3  #include <iostream>
  4   using   namespace   std;
   5   void  print(vector< int >&  vInt);
   6   int   main()
   7   {
   8       //  vIntA 
  9      vector< int >  vIntA;
  10      vIntA.push_back( 11  );
  11      vIntA.push_back( 12  );
  12      vIntA.push_back( 13  );
  13      cout <<  "   vIntA =   "  ;
  14       print(vIntA);
  15  
 16       //  vIntB 
 17      vector< int >  vIntB;
  18      vIntB.push_back( 90  );
  19      vIntB.push_back( 92  );
  20      cout<<  "   vIntB =   "  ;
  21       print(vIntB);
  22  
 23       //   vIntA 与 vIntB 交换 
 24       swap(vIntA, vIntB);
  25      cout <<  "  vIntA 与 vIntB 交换后  "  <<  endl;
  26      cout <<  "  vIntA =  "  ;
  27       print(vIntA);
  28      cout <<  "  vIntB =  "  ;
  29       print(vIntB);
  30  
 31       return   0  ;
  32   }
  33  
 34   //   vector 元素打印 
 35   void  print(vector< int >&  v)
  36   {
  37       for  ( int  i= 0 ; i<v.size(); i++ )
  38          cout<< v[i] <<  "    "   ;
  39      cout <<  endl;
  40  }

vector 的其他常用函数

  1   /*          解释:
   2   1. bool empty()  判断容器 vector 是否为空,若容器没有一个元素则返回 true, 否则返回 false
   3   2. size_type size()  当前 vector 容器的实际元素个数
   4   3. size_type max_size()  系统所允许的 vector 容器的最大元素个数
   5   4. size_type capacity()  当前可容纳的 vector 元素个数
   6   5. reference front()  vector容器的首元素(引用),要求 vector 不为空
   7   6. reference back()  vector容器的末元素(引用),要求 vector 不为空
   8   7. void pop_back()  与 push_back() 函数相反,pop_back() 函数用于删除末尾的一个容器元素
   9   */ 
 10  
 11  --------------------------------  vector 的其他常用函数
  12  #include <vector>
 13  #include <iostream>
 14   using   namespace   std;
  15   void  print(vector< int >&  v);
  16   int   main()
  17   {
  18      vector< int >  vInt;
  19       print(vInt);
  20       //   添加 5 个元素 
 21      vInt.push_back( 1  );
  22      vInt.push_back( 2  );
  23      vInt.push_back( 3  );
  24      vInt.push_back( 4  );
  25      vInt.push_back( 5  );
  26       print(vInt);
  27  
 28       //   再添加 4 个元素 
 29      vInt.push_back( 6  );
  30      vInt.push_back( 7  );
  31      vInt.push_back( 8  );
  32      vInt.push_back( 9  );
  33       print(vInt);
  34  
 35       //   调整 vector 数据空间大小 
 36      vInt.reserve( 30  );
  37       print(vInt);
  38  
 39       return   0  ;
  40   }
  41  
 42   void  print(vector< int >&  v)
  43   {
  44      cout <<  "  ----------------------  "  <<  endl;
  45      cout <<  "  empty =   "  << v.empty()<<  endl;
  46      cout <<  "  size =   "  << v.size()<<  endl;
  47      cout <<  "  max_size =   "  << v.max_size()<<  endl;
  48      cout <<  "  capacity =   "  << v.capacity()<<  endl;
  49  
 50  }

------------ vector 小结:
    vector 向量容器是一个实现数据线型存储的泛型类,除了可以使用数组方式进行元素访问外,还可以利用前向和反向迭代器
iterator/reverse_iterator ,以及 push_back 、 begin 、 end 、 erase 和 clear 等函数,对容器元素进行插入、遍历和删除操作。

    vector 缺点: vector 不适合那种 【容器元素 插入 删除 操作非常频繁】 的情况
    vector 优点: 看最前面的介绍

【好好学习,天天向上】 ||||||| 【 亮仔 到此一游 】

 

分类:  STL学习笔记

标签:  STL ,  C++ ,  容器 ,  vector

山寨STL

对于STL的掌握, 侯捷将境界分为三层: 会用,明理,能扩展。 我自己在学习STL的过程中也有类似体会,为避免初学者走弯路, 下面是个人的一些学习经验和参考书籍:
《C++标准程序库:自修教程与参考手册》 这本书既是STL学习的入门书,也是日后的重要参考手册,遇到任何STL用法方面的问题,基本上都可以在这本书上找到答案。
《Effective STL》  如果说前面这本书让你使用STL入门, 那么这本书是告诉你如何高效的使用STL以及如何规避STL的缺陷和陷阱。

看完前面的2本书, 在实际工作中尽量多用STL,经过一段时间, 基本上已经到达 "会用" 的境界了。

在 “明理” 阶段,个人推荐看《 泛型编程与STL 》,这本书是STL的著者写的, 他把STL的设计理念和架构层次解释的非常清楚,内部详细描述了STL的各种泛型需要满足的concepts, 该书也是STL实作是否符合标准的参考手册。个人建议即使你只关注“会用”STL, 也看一下这本书, 这本书会让你认识STL的本质。

最后一个阶段是扩展, 甚至自己重写STL, 参考书是 《STL源码剖析》 , 这本书是个人学习STL源码的绝佳书籍, 强烈推荐。当然看STL源码需要有一定的 “模板” 功力, 如果功力不够,可以先看下 《C++ Templates》 , 这是一本学习模板编程的标准书。

个人尝试山寨了下STL, 对STL的6大组件(containers, algorithms, iterators, functors, adaptors, allocators)都有涉及。 当然山寨STL不是为了重复造轮子,而是为了更好的理解和扩展STL。

源码下载:  SimpleSTL

 

 

分类:  STL&GP

标签:  STL C++

STL学习笔记

STL学习笔记--vector

摘要: vector 向量容器 作为数组的一个泛化推广的 vector 容器,不仅可以进行数组一样的元素随机访问,还可以在容器的尾端插入新元素,是一个实现了 Random Access Container 和 Back Insertion Sequence 概念的模型 vector 是一种简单、高效的容器。在尾端插入和删除元素,算法时间复杂度为 O(1) 常数阶,其他元素的插入删除为 O(n) 线型阶,其中 n 为 vector 容器的元素个数。 vector 具有自动的内存管理功能,对于元素的插入和删除,可动态调整所占用的内存空间。 vector 容器的 C++ 标准头文件为 vector, 因此. 阅读全文

posted @  2013-04-03 19:50  music__liang 阅读(52) |  评论 (0)   编辑

STL学习笔记--前篇

摘要: 终于,我又开始更新博客了。。。之所以没更新,是因为没学到什么知识,马上就毕业了,必须【闭关】学点东西啊。 以前 ,总觉得 STL 这类东西,等毕业了在去学还来得及。。。但是,笔试了几家公司之后,觉得很多公司都看重这方面的知识, STL 应该在【毕业之前】就学习。 还有,就是觉得 STL 好抽象,不知道从哪开始。 大家都一样的,面对未知的东西,在学习或者操作之前,我们总是会感到迷茫,这很正常。。只要能坚持,能不断去寻找适合的学习的资料、学习的方法,我们总会有突破的。。。哎。这个,只能靠自己了。多看书,敲代码吧。。我也正在这样进行中。。。 在学习 STL 之前,总得有点模板的概念吧。。... 阅读全文

posted @  2013-04-03 15:39  music__liang 阅读(26) |  评论 (0)   编辑

C++

 

C++中基于Crt的内存泄漏检测

摘要: 尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询。 阅读全文

posted @  2013-02-25 22:33  Richard Wei 阅读(963) |  评论 (1)   编辑

 

在C++中实现事件(委托)(续)

摘要: 在上文 在C++中实现事件(委托) 中我们实现的C#里委托方式的事件处理, 虽然使用很方便,但是感觉似乎少了一点C#的味道, 下面我们尝试把它改成真正的C#版。 其实要改成真正的C#版,我们主要要做2件事, 一是吧CEventHandler放到外面,可以让外部直接构造, 二是实现operator +=和operator -= 阅读全文

posted @  2013-01-31 17:46  Richard Wei 阅读(1077) |  评论 (5)   编辑

 

在C++中实现事件(委托)

摘要: 在C++中实现回调机制的几种方式一文中,我们提到了实现回调的三种方式(C风格的回调函数, Sink方式和Delegate方式)。在面向对象开发中,delegate的方式是最灵活和方便的,因此很早就有人用复杂的模板去模拟, 实现起来很复杂。但是现在借助C++11的function和bind, 我们可以很方便的去实现。 阅读全文

posted @  2013-01-31 14:23  Richard Wei 阅读(661) |  评论 (2)   编辑

 

C++模板会使代码膨胀吗

摘要: 通过上面的分析 ,相信我们知道了为什么ATL/WTL大量使用模板,但是生成的exe还是这么小的原因 : 不是模板不会使代码膨胀,而是ATL/WTL在设计时就关注了这个问题 ,它避免了在可能生成很多模板实例的模板类中编写大量代码(有些拗口,不知道你有没有读懂^_^) 总结下 ,如果你想用模板,但是又不想 让自己最终的可执行文件变的很大, 有2种方式: (1)你的模板类不会生成很多模板实例,这样写成模板类还有意义吗? (2)你的模板类的代码量或是函数个数很少,你可以仿照ATL的方式把模板无关的东西逐层剥离。 阅读全文

posted @  2012-11-08 22:56  Richard Wei 阅读(921) |  评论 (6)   编辑

 

重构ATL中的CAutoVectorPtr, CAutoPtr和CAutoStackPtr

摘要: 看到ATL中有3个类的代码比较比较重复,在atlbase.h中,分别是CAutoVectorPtr,CAutoPtr和CAutoStackPtr,他们的功能其实很类似STL中的autoptr, 但是这里因为针对不同的分配对象而用了3个不同的类,其中CAutoVectorPtr是针对数组类型的,CAutoPtr是针对普通的非数组类型,而CAutoStackPtr针对的是_malloca分配的类型,因为最后释放方式的不同,它这里用了3份代码来实现。CAutoVectorPtr:template<typenameT>classCAutoVectorPtr{public:CAutoVect 阅读全文

posted @  2012-09-24 23:10  Richard Wei 阅读(990) |  评论 (5)   编辑

 

探索C++对象模型

摘要: 总之,拿着一把刀,庖丁解牛般的剖析语言背后的实现细节,看起来不是那么实用,但是它能让你对语言的理解更深刻。实际上ATL中大量应用上面的技术,如果没有对C++ 对象模型有比较深刻的理解,是很难深入下去的。 阅读全文

posted @  2012-09-21 23:08  Richard Wei 阅读(1538) |  评论 (3)   编辑

 

理解C++变量存储模型

摘要: 通过上面的分析,我们验证了平时C++书上关于各种类型变量存储区域的假设,简单来说就是全局变量和静态变量会被编译到可执行文件的数据节(分只读和可读写)中, 非静态的局部变量则分配在堆栈(stack)上,而new(malloc)出来的内存则分配在堆(heap)上。 阅读全文

posted @  2012-09-20 22:02  Richard Wei 阅读(1259) |  评论 (5)   编辑

 

C/C++中可变参数的原理

摘要: 从上面的例子我们可以看到,对于可变参数的函数,有2种东西需要确定,一是可变参数的数量, 二是可变参数的类型,上面的例子中,参数数量我们是在第一个参数指定的,参数类型我们是自己约定的。这种方式在实际使用中显然是不方便,于是我们就有了_vsprintf, 我们根据一个格式化字符串的来表示可变参数的类型和数量,比如C教程中入门就要学习printf, sprintf等。 总的来说可变参数给我们提供了很高的灵活性和方便性,但是也给会造成不确定性,降低我们程序的安全性,很多时候可变参数数量或类型不匹配,就会造成一些不容察觉的问题,只有更好的理解它背后的原理,我们才能更好的驾驭它。 阅读全文

posted @  2012-09-18 00:29  Richard Wei 阅读(1395) |  评论 (1)   编辑

 

C++中模块(Dll)对外暴露接口的几种方式

摘要: 当然,上面几种DLL对外暴露接口的方式本质上没有区别,都是利用PE文件的导出节来导出数据和函数,但是根据它们使用方式的不同,对外部模块来说还是有很大的区别,我们的推荐次序依次是:COM方式->导出API函数方式->导出类方式。 阅读全文

posted @  2012-08-29 19:04  Richard Wei 阅读(1301) |  评论 (0)   编辑

 

C++中实现回调机制的几种方式

摘要: 最后简单比较下上面3种实现回调的方法: 第一种Callback的方法是面向过程的,使用简单而且灵活,正如C语言本身。 第二种Sink的方法是面向对象的,在C++里使用较多, 可以在一个Sink里封装一组回调接口,适用于一系列比较固定的回调事件。 第三种Delegate的方法也是面向对象的,和Sink封装一组接口不同,Delegate的封装是以函数为单位,粒度比Sink更小更灵活。 阅读全文

posted @  2012-08-28 12:43  Richard Wei 阅读(1562) |  评论 (7)   编辑

 

C++11新特性不完全测试

摘要: 摘要: Lambda, auto, 统一初始化,智能指针,Regex, Random, function and bind, hash_map… 右值引用和Move语义, 并发(多线程库)…发布阅读全文Richard Wei 2012-06-06 17:34 发表评论 阅读全文

posted @  2012-06-06 17:34  Richard Wei 阅读(34) |  评论 (0)   编辑

 

如何判断一个C++对象是否在堆上

摘要: 摘要: 在帖子 "如何判断一个C++对象是否在堆栈上” 中, 又有人提出如何判断一个C++对象是否在堆上。阅读全文Richard Wei 2012-05-12 14:30 发表评论 阅读全文

posted @  2012-05-12 14:30  Richard Wei 阅读(38) |  评论 (0)   编辑

 

如何判断一个C++对象是否在堆栈上

摘要: 摘要: 要解答这个问题,其实就是要知道的堆栈的起始地址, 而我们知道堆栈其实就是一段有相同属性的内存页面阅读全文Richard Wei 2012-05-12 10:57 发表评论 阅读全文

posted @  2012-05-12 10:57  Richard Wei 阅读(35) |  评论 (0)   编辑

 

一个高效的内存池实现

摘要: 摘要: 在高效C++编程中看到一个不错的内存池实现方案,这里共享下,大家看看有什么不足。阅读全文Richard Wei 2012-05-05 23:23 发表评论 阅读全文

posted @  2012-05-05 23:23  Richard Wei 阅读(60) |  评论 (0)   编辑

 

引用计数的智能指针的实现与思考

摘要: 摘要: 引用计数在软件开发中是一项非常重用的技术,它可以说是无处不,我们在不知不觉中都在和它打交道,比如 Windows上的COM和Handle, Mac上的ref句柄,脚本语言中的垃圾回收技术。阅读全文Richard Wei 2012-05-05 17:04 发表评论 阅读全文

posted @  2012-05-05 17:04  Richard Wei 阅读(38) |  评论 (0)   编辑

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于STL学习笔记vector的详细内容...

  阅读:35次