剖析C++ 动态数组 vector

来源:互联网 发布:中世纪2优化九国家简介 编辑:程序博客网 时间:2024/05/21 04:17

 

     vector是c++标准模板库中的一个容器,简单来说,vector是一个能够存放多种类型的动态数组,前提是每个vector只能装一个类型,说到这里提一下python的列表和元组,个人认为python的列表要比C++和java的容器好用的多,比如java,从1.5开始支持泛型编程,更安全了,但是编译的时候还是不带泛型。python中的列表和元组是没有类型限制的,比如,我在列表中存了一个整形数(python2.5),然后我再存一个字符型也没有问题,python对列表中的数据类型没有限制。为什么python能这么玩,下篇博客会专门介绍,python的内置数据类型和用法以及python的一些有趣的bug。

1.vector的数据结构:vector是在内存中开辟连续的存储区,其基本数据结构是顺序表,这种数据结构的优点:查询快,快速定位某个元素的位置,不用挨个遍历,但是插入慢,因为我在某个位置插入一个元素要移动后面的所有元素的位置,这让我想到N多老生常谈的面试题,比如像java中的ArrayList何LinkedList的区别。其实其本质都是考数据结构的顺序表和线性表。

2.vector的属性:vector之所以称之为动态数组,要从动态和数组2个角度考虑,所谓动态,就是可以动态扩展,比如vector中有size()方法,返回vector中数据的个数还有capacity()方法,返回此vector的容量,这两个方法的区别是:就像一个杯子,当前装了多少水用size(),能装多少水用capacity()方法:上段代码,看看vector是怎么动态追加的:

 

  1. //============================================================================  
  2. // Name        : test.cpp  
  3. // Author      : zhangpeng  
  4. // Version     :  
  5. // Copyright   : Your copyright notice  
  6. // Description : vector in C++, Ansi-style  
  7. //============================================================================  
  8.  
  9. #include<stdio.h>  
  10. #include<vector>  
  11. using namespace std;  
  12. extern "C" 
  13. typedef vector<int> vec;  
  14.  
  15. int main() {  
  16.     vec va;
  17. va.reserve(20);  
  18.     printf("va capacity %d /n",va.capacity());  
  19.     printf("va size %d /n",va.size());  
  20.     for(int i = 0; i < 30; i++){  
  21.         va.push_back(i);  
  22.     }  
  23.     printf("va capacity %d /n",va.capacity());  
  24.     printf("va size %d /n",va.size());  
  25.     return 0;  

输出结果是:

va capacity 20 
va size 0 
va capacity 40 
va size 30

     这段代码的意思是:我先设定vector的容量为20(在用reserve()申请缓存区,这个缓存区是根据vector内部的动态数组确定大小的),size为0,然后我在va中追加30个元素,然后可以看到,capacity是动态增长的,当vector中的缓存不够用的时候,它就会动态的把自己的容量扩大1.5到2倍(有些书上说扩大2倍,其实不确切,或者作者没写过代码),当扩大缓存区的时候,先创建空的缓存区,然后把值拷贝到新的缓存区中,这样的操作让我想到了hibernate的merge()方法,这样的操作有弊端,比如我操作大对象,这样的话效率不高,操作基本数据类型要好些,那我们遇见复杂对象数据类型怎么办呢?我们可以操作该对象的指针,就是vector中存指针,这样效率会明显提升。

    vector中的四个相关成员函数:size() 和capacity()刚才已经介绍过了,现在介绍一下reserve和resize() ,

    reserve(n):强制vector把它的容量改为至少n个,如果当前容量大于n,泽vector忽略此操作,如果当前容量小于等于n则vector被强迫重新分配一次,因为他的容量要增加.

    resize(n):如果当前大小超出,则销毁超出部分,如果当前大小小于n,则增加默认值。

3.vector成员函数的其他操作:

c.assign(beg,end) c.assign(n,elem)

将(beg; end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。

c.at(idx) // 建议用这种操作,不要去下标。 

传回索引idx所指的数据,如果idx越界,抛出out_of_range。

c.back()

传回最后一个数据,不检查这个数据是否存在。

c.begin()

传回迭代器中的第一个数据地址。 

c.clear()

移除容器中所有数据。

c.empty()

判断容器是否为空。

c.end() //指向迭代器中末端元素的下一个,指向一个不存在元素。

c.erase(pos) // 删除pos位置的数据,传回下一个数据的位置。

c.erase(beg,end)

删除[beg,end)区间的数据,传回下一个数据的位置。

c.front()

传回第一个数据。

get_allocator

使用构造函数返回一个拷贝。

c.insert(pos,elem) //在pos位置插入一个elem拷贝,传回新数据位置

c.insert(pos,n,elem) //在pos位置插入n个elem数据,无返回值

c.insert(pos,beg,end) //在pos位置插入在[beg,end)区间的数据。无返回值

c.max_size()

c.~vector<type> 内存销毁

4.vector的迭代器:

vector必须支持迭代功能,说到迭代功能,不得不说下STL种的迭代器。

迭代器中STL中扮演着很重要的角色. STL的核心思想就是:将数据结构和算法分离。而迭代器就是作为数据结构和算法的粘合层而存在的。在STL中,每一个容器而有一个自己的迭代器, 而vector的迭代器就是一个普通的指针。所以在vector中实现迭代功能就非常的简单了。代码如下:

 

  1. vec::iterator iter = va.begin();  
  2. int i = 0;  
  3. while(iter != va.end()){  
  4.     printf("va[%d] = %d /n ",i,*iter);  
  5.     iter ++;  
  6.     i++;  

5.回收vector的过剩内存:

这样做的目的是把vector的容量减少到需要的容量:

vector<int>( va).swap(va);

解释一下:我们先建立一个va的拷贝,vector<int>(va),这是通过vector的拷贝构造函数实现的,是va的一份拷贝,由于使用它的拷贝构造函数只是拷贝元素需要的内存,所以这个临时的va没有多余的容量,然后临时拷贝的va和va进行数据交换,然后临时的va中有以前没有用的容量,然后销毁va的临时拷贝,回收过剩的内存。你可以试一下(vector<int>(va).swap(va)).capacity();

今天就到这,问个问题,我要拿到vector的首地址除了用迭代器还能用其他办法吗?