转自http://blog.csdn.net/whz_zb/article/details/6827999

vector简介

vector是STL中最常见的容器,它是一种顺序容器,支持随机访问。vector是一块连续分配的内存,从数据安排的角度来讲,和数组极其相似,不同的地方就是:数组是静态分配空间,一旦分配了空间的大小,就不可再改变了;而vector是动态分配空间,随着元素的不断插入,它会按照自身的一套机制不断扩充自身的容量。

vector的扩充机制:按照容器现在容量的一倍进行增长。vector容器分配的是一块连续的内存空间,每次容器的增长,并不是在原有连续的内存空间后再进行简单的叠加,而是重新申请一块更大的新内存,并把现有容器中的元素逐个复制过去,然后销毁旧的内存。这时原有指向旧内存空间的迭代器已经失效,所以当操作容器时,迭代器要及时更新。

vector的数据结构

vector数据结构,采用的是连续的线性空间,属于线性存储。他采用3个迭代器_First、_Last、_End来指向分配来的线性空间的不同范围,下面是声明3个迭代器变量的源代码。

template<class _Ty, class _A= allocator< _Ty> > 
class vector{ 
    ... 
    protected: 
    iterator _First, _Last, _End; 
};

_First指向使用空间的头部,_Last指向使用空间大小(size)的尾部,_End指向使用空间容量(capacity)的尾部。例如:

int data[6]={3,5,7,9,2,4}; 
vector<int> vdata(data, data+6); 
vdata.push_back(6); 
...

vector初始化时,申请的空间大小为6,存放下了data中的6个元素。当向vdata中插入第7个元素“6”时,vector利用自己的扩充机制重新申请空间,数据存放结构如图1所示:

图1 扩充后的vector内存结构

简单描述一下。当插入第7个元素“6”时,vector发现自己的空间不够了,于是申请新的大小为12的内存空间(自增一倍),并将前面已有数据复制到新空间的前部,然后插入第7个元素。此时_Last迭代器指向最后一个有效元素,而_End迭代器指向vector的最后有效空间位置。我们利用vector的成员函数size可以获得当前vector的大小,此时为7;利用capacity成员函数获取当前vector的容量,此时为12。

vector容器类型
vector容器是一个模板类,可以存放任何类型的对象(但必须是同一类对象)。vector对象可以在运行时高效地添加元素,并且vector中元素是连续存储的。
vector的构造
函数原型:
template<typename T>
   explicit vector();                                 // 默认构造函数,vector对象为空
   explicit vector(size_type n, const T& v = T());    // 创建有n个元素的vector对象
   vector(const vector& x);
   vector(const_iterator first, const_iterator last);

注:vector容器内存放的所有对象都是经过初始化的。如果没有指定存储对象的初始值,那么对于内置类型将用0初始化,对于类类型将调用其默认构造函数进行初始化(如果有其它构造函数而没有默认构造函数,那么此时必须提供元素初始值才能放入容器中)。
举例:
vector<string> v1;         // 创建空容器,其对象类型为string类
vector<string> v2(10);     // 创建有10个具有初始值(即空串)的string类对象的容器
vector<string> v3(5, "hello"); // 创建有5个值为“hello”的string类对象的容器
vector<string> v4(v3.begin(), v3.end());  // v4是与v3相同的容器(完全复制)
vector的操作(下面的函数都是成员函数)
 
bool empty() const;                    // 如果为容器为空,返回true;否则返回false
size_type max_size() const;            // 返回容器能容纳的最大元素个数
size_type size() const;                // 返回容器中元素个数  
size_type capacity() const;            // 容器能够存储的元素个数,有:capacity() >= size()  
void reserve(size_type n);             // 确保capacity() >= n
void resize(size_type n, T x = T());   // 确保返回后,有:size() == n;如果之前size()<n,那么用元素x的值补全。
reference front();                     // 返回容器中第一个元素的引用(容器必须非空)
const_reference front() const;                   
reference back();                      // 返回容器中最后一个元素的引用(容器必须非空)
const_reference back() const;
reference operator[](size_type pos);   // 返回下标为pos的元素的引用(下标从0开始;如果下标不正确,则属于未定义行为。
const_reference operator[](size_type pos) const; 
reference at(size_type pos);           // 返回下标为pos的元素的引用;如果下标不正确,则抛出异常out_of_range
const_reference at(size_type pos) const;
            
void push_back(const T& x);            // 向容器末尾添加一个元素          
void pop_back();                       // 弹出容器中最后一个元素(容器必须非空)
// 注:下面的插入和删除操作将发生元素的移动(为了保持连续存储的性质),所以之前的迭代器可能失效
iterator insert(iterator it, const T& x = T());        // 在插入点元素之前插入元素(或者说在插入点插入元素)
void insert(iterator it, size_type n, const T& x);     // 注意迭代器可能不再有效(可能重新分配空间)
void insert(iterator it, const_iterator first, const_iterator last);
iterator erase(iterator it);           // 删除指定元素,并返回删除元素后一个元素的位置(如果无元素,返回end())
iterator erase(iterator first, iterator last); // 注意:删除元素后,删除点之后的元素对应的迭代器不再有效。
void clear() const;                    // 清空容器,相当于调用erase( begin(), end())
void assign(size_type n, const T& x = T());   // 赋值,用指定元素序列替换容器内所有元素
void assign(const_iterator first, const_iterator last);
const_iterator begin() const;          // 迭代序列
iterator begin();
const_iterator end() const;
iterator end();
const_reverse_iterator rbegin() const;
reverse_iterator rbegin();
const_reverse_iterator rend() const; 
reverse_iterator rend();
vector对象的比较(非成员函数)
针对vector对象的比较有六个比较运算符:operator==、operator!=、operator<、operator<=、operator>、operator>=。
其中,对于operator==和operator!=,如果vector对象拥有相同的元素个数,并且对应位置的元素全部相等,则两个vector对象相等;否则不等。
对于operator<、operator<=、operator>、operator>=,采用字典排序策略比较。

注:其实只需要实现operator==和operator!=就可以了,其它可以根据这两个实现。因为,operator!= (lhs, rhs) 就是 !(lhs == rhs),operator<=(lhs, rhs) 就是 !(rhs < lhs),operator>(lhs, rhs) 就是 (rhs < lhs),operator>=(lhs, rhs) 就是 !(lhs, rhs)。
vector类的迭代器

   vector类的迭代器除了支持通用的前缀自增运算符外,还支持算术运算:it + n、it - n、it2 - it1。注意it2 - it1返回值为difference_type(signed类型)。
注意,任何改变容器大小的操作都可能造成以前的迭代器失效。
应用示例

1.vector 的数据的存入和输出:

#include<stdio.h>
#include<vector>
#include <iostream>

using namespace std;

void main()

{

int i = 0;

vector<int> v;

for( i = 0; i < 10; i++ )

{

v.push_back( i );//把元素一个一个存入到vector中

}

for( i = 0; i < v.size(); i++ )//v.size() 表示vector存入元素的个数

{

cout << v[ i ] << "  "; //把每个元素显示出来

}

cout << endl;

}

注:你也可以用v.begin()和v.end() 来得到vector开始的和结束的元素地址的指针位置。你也可以这样做:

vector<int>::iterator iter;

for( iter = v.begin(); iter != v.end(); iter++ )

{
    cout << *iter << endl;
}

2. 对于二维vector的定义。

1)定义一个10个vector元素,并对每个vector符值1-10。

#include<stdio.h>
#include<vector>
#include <iostream>

using namespace std;

void main()
{
 int i = 0, j = 0;

//定义一个二维的动态数组,有10行,每一行是一个用一个vector存储这一行的数据。

所以每一行的长度是可以变化的。之所以用到vector<int>(0)是对vector初始化,否则不能对vector存入元素。
 vector< vector<int> > Array( 10, vector<int>(0) );

for( j = 0; j < 10; j++ )
 {
  for ( i = 0; i < 9; i++ )
  {
   Array[ j ].push_back( i );
  }
 }

for( j = 0; j < 10; j++ )
 {
  for( i = 0; i < Array[ j ].size(); i++ )
  {
   cout << Array[ j ][ i ] << "  ";
  }
  cout<< endl;
 }
}

2)定义一个行列都是变化的数组。

#include<stdio.h>
#include<vector>
#include <iostream>

using namespace std;

void main()
{
 int i = 0, j = 0;

vector< vector<int> > Array;
 vector< int > line;
 for( j = 0; j < 10; j++ )
 {
  Array.push_back( line );//要对每一个vector初始化,否则不能存入元素。
  for ( i = 0; i < 9; i++ )
  {
   Array[ j ].push_back( i );
  }
 }

for( j = 0; j < 10; j++ )
 {
  for( i = 0; i < Array[ j ].size(); i++ )
  {
   cout << Array[ j ][ i ] << "  ";
  }
  cout<< endl;
 }
}

3.综合一点的例子。

#include <iostream>
#include <cassert>
#include <vector>

using namespace std;

int main()
{
    vector<int> v(5, 1);
    vector<int> v2(v.begin(), v.end());
    
    assert(v == v2);
    
    cout<<"> Before operation"<<endl;
    for(vector<int>::const_iterator it = v.begin(); it < v.end(); ++it)
        cout<<*it<<endl;

//v.insert(v.begin() + 3, 4, 2);

v.insert(v.begin() + 3, 1, 2);
    v.insert(v.begin() + 4, 1, 3);
    v.insert(v.begin() + 5, 1, 4);

v.insert(v.begin() + 6, 1, 5);

    cout<<"> After insert"<<endl;
    for(vector<int>::size_type i = 0; i < v.size(); ++i)
        cout<<v[i]<<endl;
    
    vector<int>::iterator it1 = v.erase(v.begin() + 3, v.begin() + 6);//删除的是第4,5,6三个元素
    assert(*it1 == 5);
    cout<<"> After erase"<<endl;
    for(vector<int>::size_type j = 0; j != v.size(); ++j)
        cout<<v[j]<<endl;
    
    assert(v.begin() + v.size() == v.end());
    assert(v.end() - v.size() == v.begin());
    assert(v.begin() - v.end() == -vector<string>::difference_type(v.size()));
    
    return 0;
}

程序说明:上面第3个程序中用了三个循环输出容器中的元素,每个循环的遍历方式是不一样的。特别需要说明的是,第二个循环在条件判断中使用了size() 函数,而不是在循环之前先保存在变量中再使用。之所以这样做,有两个原因:其一,如果将来在修改程序时,在循环中修改了容器元素个数,这个循环仍然能很好 地工作,而如果先保存size()函数值就不正确了;其二,由于这些小函数(其实现只需要一条返回语句)基本上都被声明为inline,所以不需要考虑效率问题。

附录1

vector是一个标准库中的容器,使用时需要包含#include <vector>头文件。

vector是一个类模板而不是一种数据类型,对它的定义,需要指定类型。

vector(向量)是 C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,

当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间的目的.

1、vector对象的定义和初始化

vector类定义了好几种构造函数,并且与string类型相类似,如下所示:

操作调用方式

操作说明

Vector<T> v1;

Vector保存类型为T的对象。默认构造函数v1为空

Vector<T> v2(v1);

V2是v1的一个副本

Vector<T> v3(n , i);

V3包含n个值为i的元素

Vector<T> v4(n);

V4含有值初始化的元素的n个副本

注:对C++的容器来说,动态添加元素的效率,要比直接静态初始化元素的效率高

例1.1 :声明一个int向量以替代一维的数组:vector <int> a;(等于声明了一个int数组a[],大小没有指定,可以动态的向里面添加删除)。

例1.2: 用vector代替二维数组.其实只要声明一个一维数组向量即可,而一个数组的名字其实代表的是它的首地址,所以只要声明一个地址的向量即可,即:vector <int *> a.同理想用向量代替三维数组也是一样,vector <int**>a;再往上面依此类推.

备注:

在用vector的过程中我碰到了一个问题,特此列出讨论:

1)

vector <int > a;

int b = 5;

a.push_back(b);

此时若对b另外赋值时不会影响a[0]的值

2)

vector <int*> a;
                      int *b;
                      b= new int[4];
                      b[0]=0;
                      b[1]=1;
                      b[2]=2;
                      a.push_back(b);
                      delete b;          //释放b的地址空间
                      for(int i=0 ; i <3 ; i++)
                      {
                            cout<<a[0][i]<<endl;
                      }

此时输出的值并不是一开始b数组初始化的值,而是一些无法预计的值.

分析:根据1) 2)的结果,可以想到,在1)中,   往a向量中压入的是b的值,即a[0]=b,此时a[0]和b是存储在两个不同的地址中的.因此改变b的值不会影响a[0];而在2)中,因为是把一个地址(指针)压入向量a,即a[0]=b,因此释放了b的地址也就释放了a[0]的地址,因此a[0]数组中存放的数值也就不得而知了.

2、vector对象的操作

vector标准库提供了许多类似于string对象的操作,如下所示是一部分:

操作调用方式

操作说明

v.empty()

判断v是否为空

v.size()

返回v中元素的个数

v.push_back(t)

向v的末尾添加一个元素

V[n]

返回v中位置为n的元素

V1 = v2

把v1中元素替换为v2中元素副本

V1==v2

判断是否相等

!=, <, <=, >, >=

直接用于vector对象的相互比较

1.push_back   在数组的最后添加一个数据
2.pop_back    去掉数组的最后一个数据 
3.at                得到编号位置的数据
4.begin           得到数组头的指针
5.end             得到数组的最后一个单元+1的指针
6.front        得到数组头的引用
7.back            得到数组的最后一个单元的引用
8.max_size     得到vector最大可以是多大
9.capacity       当前vector分配的大小
10.size           当前使用数据的大小
11.resize         改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve      改变当前vecotr所分配空间的大小
13.erase         删除指针指向的数据项
14.clear          清空当前的vector
15.rbegin        将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend          将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty        判断vector是否为空
18.swap         与另一个vector交换数据

注,以下是一些需要注意的地方

Ø vector和string一样,长度、下标等类型是size_type,但是vector获取size_type时,需要指定类型,如vector<int>::size_type这样的方式

Ø vector的下标操作,例如v[i],只能用于操作已经存在的元素,可以进行覆盖、获取等,但是不能通过v[i++]这种方式来给一个vector容器添加元素,该功能需要用push_back操作完成,下标不具备该功能

Ø C++程序员习惯优先使用!=而不是<来编写循环判断条件

附录2

C++ vector 排序

C++中当 vector 中的数据类型为基本类型时我们调用std::sort函数很容易实现 vector中数据成员的升序和降序排序,然而当vector中的数据类型为自定义结构体类型时,我们该怎样实现升序与降序排列呢?有两种方法,下面的例子能很好的说明: 方法1:
我们直接来看代码吧,比较简单,容易理解:
#include “stdafx.h”
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;
struct AssessTypeInfo
{
unsigned int m_uiType; //类型ID
char m_szName[64]; //类型名称
unsigned int m_uiTotal; //总分数

bool operator < (const AssessTypeInfo& rhs ) const //升序排序时必须写的函数
{
return m_uiType < rhs.m_uiType;
}
bool operator > (const AssessTypeInfo& rhs ) const //降序排序时必须写的函数
{
return m_uiType > rhs.m_uiType;
}
}
int main()
{
vector<AssessTypeInfo > ctn ;

AssessTypeInfo a1;
a1.m_uiType=1;
AssessTypeInfo a2;
a2.m_uiType=2;

AssessTypeInfo a3;
a3.m_uiType=3;

ctn.push_back(a1);
ctn.push_back(a2);
ctn.push_back(a3);
//升序排序
sort(ctn.begin(), ctn.end(),less<AssessTypeInfo>()) ; //或者sort(ctn.begin(), ctn.end()) 默认情况为升序

for ( int i=0; i<3; i++ )
printf(”%d\n”,ctn[i].m_uiType);

//降序排序
sort(ctn.begin(), ctn.end(),greater<AssessTypeInfo>()) ;

for ( int i=0; i<3; i++ )
printf(”%d\n”,ctn[i].m_uiType);

return 0 ;
}
以上方法就可以实现升序排序,输出结果为 1 2 3
降序排序结果3 2 1。
方法2 : 不修改结构体或类的定义部分,我们用函数对象来实现:
#include “stdafx.h”
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;
struct AssessTypeInfo
{
unsigned int m_uiType; //类型ID
char m_szName[64]; //类型名称
unsigned int m_uiTotal; //总分数
};

bool lessmark(const AssessTypeInfo& s1,const AssessTypeInfo& s2)
{
return s1.m_uiType < s2.m_uiType;
}
bool greatermark(const AssessTypeInfo& s1,const AssessTypeInfo& s2)
{
return s1.m_uiType > s2.m_uiType;
}
int main()
{
vector<AssessTypeInfo > ctn ;

AssessTypeInfo a1;
a1.m_uiType=1;
AssessTypeInfo a2;
a2.m_uiType=2;

AssessTypeInfo a3;
a3.m_uiType=3;

ctn.push_back(a1);
ctn.push_back(a2);
ctn.push_back(a3);

sort(ctn.begin(), ctn.end(),lessmark) ; //升序排序

for ( int i=0; i<3; i++ )
printf(”%d\n”,ctn[i].m_uiType);

sort(ctn.begin(), ctn.end(),greatermark) ; //降序排序

return 0 ;
}

以上方法就可以实现升序排序,输出结果为 1 2 3
降序排序结果3 2 1。
方法2是一种比较简单的方法。
以上两种方法您可根据您自己的需求选择,并且以上两种方法在VC++6.0环境下编译通过,也是自己在实践过程中的总结,如有不妥的地方,欢迎您指出,至于为什么这样使用,请参考 stl算法中sort 部分。

(6)C++ Vector排序

  1. vector< int > vi ;
  2. vi.push_back(1);
  3. vi.push_back(3);
  4. vi.push_back(0);
  5. sort(vi.begin() , vi.end()); /// /小到大
  6. reverse(vi.begin(),vi.end()) /// 从大道小

(7)顺序访问

  1. vector < int > vi ;
  2. for( int i = 0 ; i < 10 ; i ++)
  3. {
  4. vector.push_back(i);
  5. }
  6. for(int i = 0 ; i < 10 ; i ++) /// 第一种调用方法
  7. {
  8. cout <<vector[i] <<" " ;
  9. }
  10. for(vector<int>::iterator it = vi.begin() ;
  11. it !=vi.end() ; it++) ///第二种调用方法
  12. {
  13. cout << *it << " " ;
  14. }

(8)寻找

  1. vector < int > vi ;
  2. for( int i = 0 ; i < 10 ; i ++)
  3. {
  4. vector.push_back(i);
  5. }
  6. vector < int >::interator it = find(vi.begin() , vi.end,3) ;
  7. cout << *it << endl ; ///返回容器内找到值的位置。

(9)使用数组对C++ Vector进行初始化

  1. int i[10] ={1,2,3,4,5,6,7,78,8} ;
  2. ///第一种
  3. vector<int> vi(i+1,i+3); ///从第2个元素到第三个元素
  4. for(vector <int>::interator it = vi.begin() ;
  5. it != vi.end() ; it++)
  6. {
  7. cout << *it <<" " ;
  8. }

(10) 结构体类型

  1. struct temp
  2. {
  3. public :
  4. string str ;
  5. public :
  6. int id ;
  7. }tmp
  8. int main()
  9. {
  10. vector <temp> t ;
  11. temp w1 ;
  12. w1.str = "Hellowor" ;
  13. w1.id = 1 ;
  14. t.push_back(t1);
  15. cout << w1.str << "," <<w1.id <<endl ;
  16. return 0 ;
  17. }

转载于:https://www.cnblogs.com/xcw0754/p/4227238.html

C++ vector类详解相关推荐

  1. OpenCV Mat类详解和用法(官网原文)

    参考文章:OpenCV Mat类详解和用法 我马克一下,日后更 官网原文链接:https://docs.opencv.org/3.2.0/d6/d6d/tutorial_mat_the_basic_i ...

  2. STL中map和string, vector 用法详解

    1. map 用法详解 std map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成 ...

  3. Cocos2d之Node类详解之节点树(二)

    一.声明 本文属于笔者原创,允许读者转载和分享,只要注明文章来源即可. 笔者使用cocos2d框架的cocos2d-x-3.3rc0版本的源代码做分析.这篇文章承接上篇<Cocos2d之Node ...

  4. OpenCV Mat类详解和用法

    OpenCV Mat类详解和用法 我们有多种方法可以获得从现实世界的数字图像:数码相机.扫描仪.计算机体层摄影或磁共振成像就是其中的几种.在每种情况下我们(人类)看到了什么是图像.但是,转换图像到我们 ...

  5. 转载:c+string类详解

    C++ string 类详解 </h1><div class="clear"></div><div class="postBod ...

  6. JDBC学习笔记02【ResultSet类详解、JDBC登录案例练习、PreparedStatement类详解】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  7. JDBC学习笔记01【JDBC快速入门、JDBC各个类详解、JDBC之CRUD练习】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  8. Android复习14【高级编程:推荐网址、抠图片上的某一角下来、Bitmap引起的OOM问题、三个绘图工具类详解、画线条、Canvas API详解(平移、旋转、缩放、倾斜)、矩阵详解】

    目   录 推荐网址 抠图片上的某一角下来 8.2.2 Bitmap引起的OOM问题 8.3.1 三个绘图工具类详解 画线条 8.3.16 Canvas API详解(Part 1) 1.transla ...

  9. Java中的Runtime类详解

    Java中的Runtime类详解 1.类注释 /**Every Java application has a single instance of class Runtime that allows ...

最新文章

  1. Nginx学习之二-配置项解析及编程实现
  2. spring 判断非空提示断言
  3. 对移动APP开发的需求分析的观点及见解
  4. python六十五:描述符(__get__, __set__, __delete__)
  5. python 中的 for-else 和 while-else 语句
  6. dubbo源码解析(四十一)集群——Mock
  7. cad快速看图能合并图纸吗_怎样才能把2张CAD图纸合并
  8. 运维人员须熟悉的38个运维工具汇总
  9. HBuilderX快捷键大全
  10. Error launching IDEA
  11. QT The inferior stopped because it received a signal from the operating system.
  12. I.MX6ULL ARM驱动开发---platfrom设备驱动
  13. 伸缩门遥控器c语言程序,伸缩门遥控器匹配方法是什么呢? 如何学会电动门的遥控编码...
  14. MySQL(查询语句,关键字)
  15. 台式计算机cpu功率,如何计算主机所需的功率? ?
  16. 找工作的一些感悟——前端小菜的成长
  17. 计算机毕业设计ssm+vue基本微信小程序的快递柜管理系统 uniapp 小程序
  18. dnf压爆服务器挑战网站,DNF手游压爆服务器挑战网址分享
  19. 25条最简单却最有用的代码,看了能少走几年弯路!
  20. Windows 8.1 归档 —— Step 3 软件的选择与安装

热门文章

  1. HDU2795 Billboard
  2. .Net环境下的缓存技术介绍 (转)
  3. Windows平台下 找回已丢失的MySql root 用户密码
  4. FastReport.Net 使用字符串
  5. ubuntu 重定向
  6. 5. 多线程程序如何让 IO 和“计算”相互重叠,降低 latency?
  7. VC的Win32控制台程序中使用MFC库文件
  8. 蓝桥杯 2011年第二届C语言初赛试题(2)
  9. Windows、Linux和MAC的CR, LF, CR/LF换行符
  10. linux javaweb环境单价,linux(centos)下Java Web环境开发