C++ STL之vector

来源:互联网 发布:三国演义电视剧 知乎 编辑:程序博客网 时间:2024/06/06 05:16

1、vector
vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机存取(即使用[]操作符访问其中的元素),但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝(复杂度是O(n)),另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。这些都大大影响了vector的效率。

vector不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector类型的每一种都指定了其保存元素的类型。因此,vector和vector 都是数据类型。

为了可以使用vector,必须在你的头文件中包含下面的代码:

#include <vector>

vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:

using std::vector;vector<int> vInts;

或者连在一起,使用全名:

std::vector<int> vInts;

建议使用全局的命名域方式:

using namespace std;

**2、Vector成员函
构造函数:

vector();vector( size_type num, const TYPE &val );vector( const vector &from );vector( input_iterator start, input_iterator end );

C++ Vectors可以使用以下任意一种参数方式构造:
无参数 - 构造一个空的vector,
数量(num)和值(val) - 构造一个初始放入num个值为val的元素的Vector
vector(from) - 构造一个与vector from 相同的vector
迭代器(start)和迭代器(end) - 构造一个初始值为[start,end)区间元素的Vector(注:半开区间).

vector<Elem> c  //创建一个空的vector。vector <Elem> c1(c2)  //复制一个vector。vector <Elem> c(n)  //创建一个vector,含有n个数据,数据均已缺省构造产生。vector <Elem> c(n, elem)  // 创建一个含有n个elem拷贝的vector。vector <Elem> c(beg,end)  //创建一个以[beg;end)区间的vector。c.~ vector <Elem>()   //销毁所有数据,释放内存。

运算符语法:

v1 == v2v1 != v2v1 <= v2v1 >= v2v1 < v2v1 > v2 v[]

C++ Vectors能够使用标准运算符: ==, !=, <=, >=, <, 和 >. 要访问vector中的某特定位置的元素可以使用 [] 操作符.
两个vectors被认为是相等的,如果:
它们具有相同的容量
所有相同位置的元素相等.
vectors之间大小的比较是按照词典规则.

void assign( input_iterator start, input_iterator end );void assign( size_type num, const TYPE &val );

ssign(beg,end) 将[beg; end)区间中的数据赋值给c
c.assign(n,elem) 将n个elem的拷贝赋值给c,函数将会清除掉为vector赋值以前的内容

TYPE at( size_type loc );

c.at(idx) 传回索引idx所指的数据,如果idx越界,抛出out_of_range。at() 函数 比 [] 运算符更加安全, 因为它不会让你去访问到Vector内越界的元素

vector<int> v( 5, 1 );for( int i = 0; i < 10; i++ ) {cout << "Element " << i << " is " << v[i] << endl;}

这段代码访问了vector末尾以后的元素,这将可能导致很危险的结果.以下的代码将更加安全:

vector<int> v( 5, 1 );for( int i = 0; i < 10; i++ ) {cout << "Element " << i << " is " << v.at(i) << endl;}
TYPE back();

c.back() 函数返回当前vector最末一个元素的引用,不检查这个数据是否存在。

vector<int> v;for( int i = 0; i < 5; i++ ) {v.push_back(i);}cout << "The first element is " << v.front()      << " and the last element is " << v.back() << endl;//这段代码产生如下结果:The first element is 0 and the last element is 4
iterator begin();

s.begin()函数返回一个指向当前vector起始元素的迭代器.例如,下面这段使用了一个迭代器来显示出vector中的所有元素:

vector<int> v1( 5, 789 );vector<int>::iterator it;for( it = v1.begin(); it != v1.end(); it++ )cout << *it << endl;
size_type capacity();

c.capacity() 返回当前vector在重新进行内存分配以前所能容纳的元素数量.

void clear();

c.clear()函数删除当前vector中的所有元素.

bool empty();

如果当前vector没有容纳任何元素,则empty()函数返回true,否则返回false.例如,以下代码清空一个vector,并按照逆序显示所有的元素:

vector<int> v;for( int i = 0; i < 5; i++ ) {    v.push_back(i);}while( !v.empty() ) {    cout << v.back() << endl;    v.pop_back();}
iterator end();

c.end()函数返回一个指向当前vector末尾元素的下一位置的迭代器.注意,如果你要访问末尾元素,需要先将此迭代器自减1.

iterator erase( iterator loc );iterator erase( iterator start, iterator end );

erase函数要么删作指定位置loc的元素,要么删除区间[start, end)的所有元素.返回值是指向删除的最后一个元素的下一位置的迭代器.例如
指向迭代器中的最后一个数据地址。

// 创建一个vector,置入字母表的前十个字符vector<char> alphaVector;for( int i=0; i < 10; i++ )    alphaVector.push_back( i + 65 );int size = alphaVector.size();vector<char>::iterator startIterator;vector<char>::iterator tempIterator;for( int i=0; i < size; i++ ){    tartIterator = alphaVector.begin();    alphaVector.erase( startIterator );    // Display the vector    for( tempIterator = alphaVector.begin(); tempIterator != alphaVector.end(); tempIterator++ )    cout << *tempIterator;    cout << endl;} /*这段代码将会显示如下输出:BCDEFGHIJCDEFGHIJDEFGHIJEFGHIJFGHIJGHIJHIJIJJ*/
TYPE front();

front()函数返回当前vector起始元素的引用

allocator_type get_allocator();

get_allocator() 函数返回当前vector的内存分配器.在STL里面一般不会调用new或者alloc来分配内存,而且通过一个allocator对象的相关方法来分配.

vector<int>v3( 3, 1, v2.get_allocator( ));//把V2的内存分配器作为一个参数参与构造V3。这样,它们两个用一个内存分配器了,使用构造函数返回一个拷贝。
iterator insert( iterator loc, const TYPE &val );void insert( iterator loc, size_type num, const TYPE &val );void insert( iterator loc, input_iterator start, input_iterator end );

insert() 函数有以下三种用法:
在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器,
在指定位置loc前插入num个值为val的元素
在指定位置loc前插入区间[start, end)的所有元素 .
c.insert(pos,elem)
c.insert(pos,n,elem)
c.insert(pos,beg,end)

//创建一个vector,置入字母表的前十个字符vector<char> alphaVector;for( int i=0; i < 10; i++ )alphaVector.push_back( i + 65 );//插入四个C到vector中vector<char>::iterator theIterator = alphaVector.begin();alphaVector.insert( theIterator, 4, 'C' );//显示vector的内容for( theIterator = alphaVector.begin(); theIterator != alphaVector.end(); theIterator++ )cout << *theIterator;/*这段代码将显示: CCCCABCDEFGHIJ*/
size_type max_size();

c.max_size() 函数返回当前vector所能容纳元素数量的最大值(译注:包括可重新分配内存).

void pop_back();

c.pop_back() 函数删除当前vector最末的一个元素

vector<char> alphaVector;for( int i=0; i < 10; i++ )    alphaVector.push_back( i + 65 );int size = alphaVector.size();vector<char>::iterator theIterator;for( int i=0; i < size; i++ ) {alphaVector.pop_back();for( theIterator = alphaVector.begin(); theIterator != alphaVector.end(); theIterator++ )      cout << *theIterator;cout << endl;}/*这段代码将显示以下输出:ABCDEFGHIABCDEFGHABCDEFGABCDEFABCDEABCDABCABA*/
void push_back( const TYPE &val );

push_back()添加值为val的元素到当前vector末尾

reverse_iterator rbegin();

rbegin函数返回指向当前vector末尾的逆迭代器.(译注:实际指向末尾的下一位置,而其内容为末尾元素的值,详见逆代器相关内容)

vector<int>v1;for(int i=1;i<=5;i++){    v1.push_back(i);}vector<int>::reverse_iterator pos;pos=v1.rbegin();cout<<*pos<<" ";pos++;cout<<*pos<<endl;//输出结果为:5 4
reverse_iterator rend();

rend()函数返回指向当前vector起始位置的逆迭代器.

vector<int>v1;for(int i=1;i<=5;i++){    v1.push_back(i);}vector<int>::reverse_iterator pos;pos=v1.rend();pos--;cout<<*pos<<" ";pos--;cout<<*pos<<endl;输出结果为:1 2
void resize( size_type size, TYPE val );

resize() 函数改变当前vector的大小为size,且对新创建的元素赋值val

void reserve( size_type size );

reserve()函数为当前vector预留至少共容纳size个元素的空间.(译注:实际空间可能大于size)
resize 与reserve的区别
reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,

#include<iostream>#include<vector>using namespace std;void main(){    vector<int>v1;for(int i=1;i<=3;i++){    v1.push_back(i);}v1.resize(5,8);//多出的两个空间都初始化为8,for(i=0;i<v1.size();i++)//resize与reserver并不会删除原先的元素以释放空间{     cout<<v1[i]<<" ";}cout<<endl;v1.reserve(7);// 新元素还没有构造,for(i=0;i<7;i++){     cout<<v1[i]<<" ";//当i>4,此时不能用[]访问元素 }cout<<endl;cout<<v1.size()<<endl;cout<<v1.capacity()<<endl;}/*输出结果为:1 2 3 8 81 2 3 8 8 -842150451 -84215045157*/
size_type size();

size() 函数返回当前vector所容纳元素的数目

void swap( vector &from );

swap()函数交换当前vector与vector from的元素

vector<int>v1,v2;for(int i=1;i<=3;i++){    v1.push_back(i);    v2.push_back(i);}v2.push_back(4);v2.push_back(5);v1.swap(v2);for(int j=0;j<v1.size();j++){    cout<<v1[j]<<" ";}cout<<endl;for(int k=0;k<v2.size();k++){    cout<<v2[k]<<" ";}cout<<endl;/*输出结果为:1 2 3 4 51 2 3*/

3、访问vector中的数据
使用两种方法来访问vector。
1、 vector::at()
2、 vector::operator[]
operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:

vector<int> v;v.reserve(10);for(int i=0; i<7; i++)    v.push_back(i);try{ int iVal1 = v[7];  // not bounds checked - will not throw int iVal2 = v.at(7); // bounds checked - will throw if out of range}catch(const exception& e){ cout << e.what();}//我们使用reserve()分配了10个int型的空间,但并不没有初始化

4、压缩一个臃肿的vector
很多时候大量的删除数据,或者通过使用reserve(),结果vector的空间远远大于实际需要的。所有需要压缩vector到它实际的大小。resize()能够增加vector的大小。Clear()仅仅能够改变缓存的大小,所有的这些对于vector释放内存等九非常重要了。如何来解决这些问题呢,让我们来操作一下。
我们可以通过一个vector创建另一个vector。让我们看看这将发生什么。假定我们已经有一个vector v,它的内存大小为1000,当我们调用size()的时候,它的大小仅为7。我们浪费了大量的内存。让我们在它的基础上创建一个vector。

std::vector<CString> vNew(v);cout << vNew.capacity();

vNew.capacity()返回的是7。这说明新创建的只是根据实际大小来分配的空间。现在我们不想释放v,因为我们要在其它地方用到它,我们可以使用swap()将v和vNew互相交换一下?

vNew.swap(v);cout << vNew.capacity();cout << v.capacity();

有趣的是:vNew.capacity()是1000,而v.capacity()是7。
现在是达到我的目的了,但是并不是很好的解决方法,我们可以像下面这么写:

std::vector<CString>(v).swap(v);

你可以看到我们做了什么?我们创建了一个临时变量代替那个命名的,然后使用swap(),这样我们就去掉了不必要的空间,得到实际大小的v。