再一次遇到 vector 这个单词; 每一次见到这个单词都感觉这个单词非常的 "高大上"; 数字遇到vector马上就可以360度旋转;

当 "电" 遇到vector,马上让交流可以变得和直流一样进行控制(德国电气工程师的矢量控制理论,目前在工控界对电机控制应用

非常广泛,是变频器控制的基础理论,可惜的是中国目前没有这方面的真正的专家, 就是IT行业中的TI公司的TMS320LF24xx系列

DSP做的事,中国的基础理论的研究真的是落后于西方发达国家很多年),而在C++中遇到这个单词,同样是高大上的感觉,马上

让我想起C语言中最复杂的部分指针; 别说指针的操作你无所谓, 就算你是C++、C#、Java的粉丝;没有指针,个人感觉就像没

有金箍棒的猴子, 幻刺模糊直接让你子弹到处乱飞。

  不瞎扯啦,开始今天的内容。

一、vector

1、作用

  vector,从翻译对应的词语: 容器, 可以知道vector是用来装东西的罐子、坛子之类的东西;联系实际,坛坛罐罐可以用来装各

种不同的东西, 可以用来盛酒, 也可以用来放酸菜(南北朝鲜的酸菜就算啦),当然你如果是土豪的话,也可以用来放钢镚;如果你

是贪官的话,也可以用来藏你给情妇写的保证书什么的。

  从C++的角度来看,vector可以用来存放不同类型的对象,例如可以把int类型的对象存放到容器里面,同样也可以将char类型的

对象存储到vector中,也可以将string对象存储到vector里面。

2、容器的定义

  vector类型是C++标准库提供的一种类型,如果要在程序中引用这种类型,当然需要“报备”, 如下所示:

#include <vector>  //引用相关的头文件
using std::vector; //方便的使用std::命名空间/名字空间中的名字vector

  报备完成后就可以名正言顺的经营啦;要使用 vector 必须指明容器里面存放的是什么类型的对象,就像在坛坛罐罐上面贴上标签

告诉别人里面存放的是什么;通过在 vector后面加上 <> 然后将对象类型写入到 <> 就可以啦, 如下所示:

vector<int> vInt;

  如上就定义了一个容器对象, 并且这个容器是用来存储int类型的对象的。

   要点:尖括号里面指出的是容器中存放的是什么类型的对象; 同时要注意的是 vector<int>是一种数据类型,

   vector可以存储的对象不仅可以是内置类型,还可以是用户的自定义类型,例如string类。

vector<string>  vString;

  同样 vector<string> 也是一种新的数据类型, 这种数据类型的对象用来存储string对象。

3、容器的初始化

  标准库提供的vector类型有多种初始化方式。

  A:  vector<T>   v1;   //容器对象v1保存类型为T的对象, 容器类型的默认构造函数初始化对象v1为空

   这样定义的话,就是定义了一个容器,里面没有任何东西,就相当于一个空的坛子、罐子。

  B:  vector<T>   v2(v1);  //容器对象v2保存类型为T的对象, 对象v2初始化为与v1一样的容器

  这样定义的话,就表示开始的时候有一个罐子v1,然后又造了一个罐子v2,v2罐子是按照罐子v1为原型造的,如果v1里面有东西

那么v2罐子里面的东西与v1罐子一样; 如果v1罐子里面没有东西,那么v2罐子里面也没有东西。

  C:  vector<T>   v3(n, i);  //容器v3保存类型为T的对象, 对象初始化为保存n个类型为T、值为 i 的对象元素

  这样定义的话,就表示下了一个明确订单, 就是告诉你,你给我造一个罐子v3, 里面放多少封(n)给情妇的保证书(i)。

  D: vector<T>   v4(n);    //容器v4保存类型为T的对象, 容器对象v4中初始化里面可以存放个数为n的T对象。

  这样的定义的话,就是下了一个明确的订单, 你给某个贪官造个罐子v4, 这个罐子可以放多少(n)封给情妇的保证书, 但是你不能

放保证书,放保证书的事情让贪官自己以后放。

Exp:

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt1;
vector<int> vInt2(vInt1);
vector<int> vInt3(,);
vector<int> vInt4(); string str("volcanol");
vector<string> vStr1;
vector<string> vStr2(vStr1);
vector<string> vStr3(,str);
vector<string> vStr4(); return ;
}

  这里需要注意的是, 对于存储string对象容器,可以用字符串字面值进行初始化, 如下所示:

vector<string>  str(, "volcanol");

4、容器元素的值的初始化

  一定要分辨清楚容器的初始化和容器元素的值的初始化两个概念, 容器的初始化可以包括两个方面:容器本身的初始化

以及容器元素的值的初始化。

  这里就细细的说一下这两个的不同之处。

  A:   vector<int>  vInt;     这里对容器对象vInt进行初始化,初始化后知道对象vInt是一个空的对象,里面暂时不能存

放任何int对象, 就是说这个坛子是一个实心的坛子,不能往里面塞东西。

  B:vector<int>  vInt1(2, 10);  这里不但对容器对象vInt1进行了初始化,同时还对容器对象里面的元素进行了初始化,

就是说容器里面存放了两个int类型的对象,且两个int对象的值均为10.  用坛坛罐罐来比喻就是罐子里面放了2个(初始化的是容器)

10元的钢镚(初始化的是容器里面的钢镚的大小)。

  C:  vector<int> vInt2(10);  这里对容器vInt2进行了初始化,而且在容器里面目前可以放10个int对象,而且这些int对象

的值为0。  用坛坛罐罐来比喻的话就是罐子里面放了10个面值为0元的钢镚。

  要点:

  如果容器存放的对象类型为内置类型,且没有提供容器元素的初始化值,那么就会初始化容器的元素值为0.

例如:

    vector<char>  vCh(1);   那么容器vCh里面就有一个元素之为'\0'的的char对象。

  如果容器存放的对象是类类型,且没有提供容器元素的初始化值,那么容器元素就会用类类型默认构造函数对容器的

元素进行初始化。

例如:

    vector<string>  vStr(2);  那么容器vStr里面就存放了两个值为空""字符串的string对象。

  如果容器存放的对象是类类型,同时类类型没有默认构造函数,且没有提供元素的初始化值, 那么标准库同样会产生

一个带初始值的对象,这个对象的每个成员都进行了初始化。(这个地方说的有点不明不白,我也是每天搞明白,有哪位大侠了

解的话,请不吝赐教)。

5、vector提供的操作

  vector类提供了类似于string类的操作。

    v.empty();  检测对象v是否为空

    v.size();  返回对象v中的元素的个数

    v.push_back(t);  往对象v中插入一个值为(t)新的元素, 这个就是动态的增加容器对象的容量,

    v[n];  访问容器中的元素, 相当于string对象的下标操作,而且容器对象下标操作符返回的是一个左值,可以进行写入操作。

    v1 = v2;  容器的赋值操作, 就是将容器对象v1的元素替换为v2中元素的副本,(这需要注意容器的大小)

    v1 == v2; 如果容器v1与v2相等,那么就返回true, 这里包括容器本身以及容器中的元素,这个必须要注意。  

     >, >=, != ,  <, <= 这些操作保持原本的意义。

Exp1:size() 和 empty()操作

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt1;
vector<int> vInt2(vInt1);
vector<int> vInt3(,);
vector<int> vInt4(); cout<<"the size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
if(vInt1.empty())
cout<<"vector<int> vInt1 is empty"<<endl;
else
cout<<"vector<int vInt1> is not empty"<<endl; return ;
}

执行结果如下所示:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out
the size of vector<int> vInt1 is:
vector<int> vInt1 is empty

Exp: push_back()操作

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt1; cout<<"the size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
if(vInt1.empty())
cout<<"vector<int> vInt1 is empty"<<endl;
else
cout<<"vector<int vInt1> is not empty"<<endl; vInt1.push_back();
cout<<"The size of vector<int> vInt1 is:"<<vInt1.size()<<endl;
if(vInt1.empty())
cout<<"vector<int> vInt1 is empty"<<endl;
else
cout<<"vector<int> vInt1 is not empty"<<endl; return ;
}

执行结果如下:

[root@localhost cpp_src]# ./a.out
the size of vector<int> vInt1 is:
vector<int> vInt1 is empty
The size of vector<int> vInt1 is:
vector<int> vInt1 is not empty

  可以发现执行 vInt1.push_back(1); 以后vInt的大小变成了1,而且不再是空的容器。

Exp:  容器的下标操作

  容器的下标操作返回的是容器里面的元素,这个要特别的注意。

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt1; for(vector<int>::size_type i=;i != ; i++)
vInt1.push_back(i); for(vector<int>::size_type i=; i != vInt1.size(); i++)
cout<<vInt1[i]<<endl; return ;
}

执行结果如下:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out

  要点:  容器的下标是从0开始计算的,   其最大值为  v.size( ) - 1;  所以上面的第二个循环可以正常执行,

当i=9的时候, i  != vInt1.size( ),因此可以进行循环;

      而当i=10 的时候,i == vInt1.size(),  for循环的条件不成立,因此跳出循环,不会产生下标越界。

  vector<int>::size_type 类型为标准库为vector类型定义的表示vector大小的类型, 在使用这个数据类型的

时候对象的类型 int 不能少,否则就会出错, 这个地方经常会被遗忘。  

Exp: 下标操作的赋值

  

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt1(); for(vector<int>::size_type i = ; i != vInt1.size(); i++)
vInt1[i]=i; for(vector<int>::size_type i=; i != vInt1.size(); i++)
cout<<vInt1[i]<<endl; cout<<"the size of vInt1 is: "<<vInt1.size()<<endl;
return ;
}

程序执行的结果是:

[root@localhost cpp_src]# ./a.out 

the size of vInt1 is: 

  要点:  vector下标操作返回的是容器里面存放的对象, 是一个左值。 

二、 迭代器  iterator

  C++标注库为访问vector提供了另外的一种机制,这个机制就是迭代器。

1、作用

  迭代器的作用就是用来访问容器中的元素。

2、迭代器的定义

  每一种类型的vector类型都定义了自己的迭代器类型,定义一个迭代器的语法如下所示:

    vector<T>::iterator  tIter;

  这样就定义了一个用于容器类型为 vector<T>的迭代器对象   tIter; tIter的数据类型是 vector<T>::iterator,

在C++中可以通过迭代器来访问容器里面的元素。

  默认定义通过上面的定义 tIter 将指向容器中的第一个元素,如果容器不为空的话。

  迭代器的概念与C语言中的指针非常类似,都有一个指向的概念,但是要严格区分两者的区别。

3、迭代器的begin和end操作

  每一种标准库定义的容器都定义了两个操作:  begin() 和 end() 操作。 begin()操作返回的迭代器指向的容器中的

第一个元素, 而end()操作则返回迭代器指向的容器中最后一个元素后面的一个位置, 通常称为 超出末端迭代器, 表明指向了一个

不存在的元素; 如果容器为空,那么迭代器的begin() 和end()操作将指向同一个位置---超出末端迭代器的位置。

4、迭代器的解引用和自增操作

  通过迭代器的解引用操作可以和下标操作符一样操作容器中的元素。

  例如:

      vector<int> vInt(3);

      vector<int>::iterator iter=vInt.begin( );   //迭代器指向 vInt容器中的第一个元素,vInt容器中一共有3个元素。

      *iter = 10;  ====》相当于  vInt[0]  = 10;

  通过移动迭代器的指向,可以访问容器中不同的元素。可以通过自增运算符来移动迭代器的指向。  

      vector<int> vInt(3);

      vector<int>::iterator iter=vInt.begin( );   //迭代器指向 vInt容器中的第一个元素,vInt容器中一共有3个元素。

      *iter = 10;  ====》相当于  vInt[0]  = 10;

         ++ iter ;

      *iter = 5;  =====>>相当于 vInt[1] = 5;

      ++ iter ;

      *iter = 1 ;  =====>>相当于  vInt[2] = 1;

       iter = vInt.begin();    =====》相当于将迭代器再次指向容器中的第一个元素,

       * iter = 3 ;  ======》 相当于vInt[0] = 3;

Exp:

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<string> vStr(); vector<string>::iterator iter=vStr.begin(); while(iter != vStr.end())
{
cin>>*iter;
++iter;
} iter=vStr.begin();
while(iter != vStr.end())
{
cout<<*iter<<endl;
++iter;
} return ;
}

程序执行结果如下:

[root@localhost cpp_src]# ./a.out
abd
abd

再次执行结果如下:

[root@localhost cpp_src]# ./a.out
volcanol hello world hi
volcanol
hello
world

5、迭代器的比较操作

  可以测试两个迭代器是否指向容器中的同一个元素,测试用的操作符为:== 和 != 。

exp:

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<string> vStr(); vector<string>::iterator iter1=vStr.begin();
vector<string>::iterator iter2=vStr.end(); if(iter1 == iter2)
cout<<"iter1 and iter2 point to the same element"<<endl;
else
cout<<"iter1 and iter2 don't point to the same element "<<endl; ++iter1;
++iter1;
++iter1; cout<<"after iter1 moved:";
if(iter1 != iter2)
cout<<"iter1 and iter2 don't point to the same element"<<endl;
else
cout<<"iter1 and iter2 point to the same element"<<endl; return ;
}

程序执行结果为:

[root@localhost cpp_src]# ./a.out
iter1 and iter2 don't point to the same element
after iter1 moved:iter1 and iter2 point to the same element

6、利用迭代器循环遍历容器中的元素

  前面我们利用下标操作符和 v.size()操作遍历了整个容器的元素,现在我们利用迭代器遍历容器。

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<string> vStr();
vector<string>::iterator iter=vStr.begin(); for(vector<string>::size_type i=; i !=vStr.size();i++)
{
cin>>vStr[i];
} while(iter != vStr.end())
{
cout<<*iter<<endl;
++iter;
} return ;
}

执行结果如如下所示:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out
kiki gaida volcanol hi world
kiki
gaida
volcanol

7、const_iterator  和 const vector<T>::iterator

看到这个题头,就会想起C语言中指针和const的结合。

  const_iterator的迭代器不能用来改变容器中元素的值,而 const vector<T>::iteraor则不能改变指向。

例如:

  vector<int> vInt(3, 10);

  vector<int>::const_iterator iter1= vInt.begin();

  *iter1 = 5 ;  //错误,不能通过const_iterator迭代器改变容器中元素的值。

  ++iter;  //正确,可以改变迭代器的指向。

而下面的情形是:

  vector<string>  vStr(3,"hi");

  const vector<string>::iterator  iter2=vStr.begin();

  *iter2 = "volcanol";  //正确,可以通过迭代器的解引用操作符来操作容器中的元素。

  iter2 =vStr.end() ;  //错误,  const 迭代器的指向不能改变。

而下面的情形是:

  const vector<int>  vInt(5,1);

     vector<int>::iterator  iter=vInt.begin();    //错误,不能这样定义

exp:

 #include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
const vector<int> vInt(); //ok,vInt[i]=0;
cout<<vInt[]<<endl; vector<int>::iterator iter=vInt.begin();
*iter = ;
cout<<vInt[]<<endl; return ;
}

编译的时候提示:

[root@localhost cpp_src]# g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:: 错误:请求从 ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int, std::allocator<int> > >’ 转换到非标量类型 ‘__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >’

  提示16行错误。

 

而下面的情形是:

  vector<int>  vInt(10,1);

  const vector<int>::const_iterator  iter=vInt.begin();  //正确,这样可以定义

这个地方需要注意, 第一个const指出的是 iter的指向不能改变, 第二个const_iterator 指出不能通过 *iter 改变容器中

元素的值。

要点:

  const修饰时迭代器和类型和容器内元素的类型要一致,如果元素不可改变,那么就不能定义可以改变容器元素的迭代器来

访问容器中的元素。

8、迭代器支持算术运算

  可以给迭代器进行 +n 和-n 的操作,就和C语言中的指针的加法、减法运算类似。

[root@localhost cpp_src]# cat test.cpp
#include <iostream>
#include <string>
#include <vector> using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector; int main()
{
vector<int> vInt();
vector<int>::iterator iter=vInt.begin(); for(;iter != vInt.end(); ++iter)
cin>>*iter; iter=vInt.begin();
iter = iter + vInt.size()/;
cout<<*iter<<endl; iter = iter - ;
cout<<*iter<<endl; return ;
}

执行结果如下所示:

[root@localhost cpp_src]# g++ test.cpp
[root@localhost cpp_src]# ./a.out

  今天关于vector和迭代器就描述到这里,后续内容,未完待续..........................

C++_系列自学课程_第_5_课_vector容器_《C++ Primer 第四版》的更多相关文章

  1. C++_系列自学课程_第_7_课_数组_《C++ Primer 第四版》

    说到数组,大家应该都很熟悉,在C.Pascal.Java等语言中,都有数组的概念.在C++中也提供了对数组的支持.数组简单来说就是一堆相同 数据类型对象的集合. 这里要把握住两个要点: 相同的数据类型 ...

  2. C++_系列自学课程_第_6_课_bitset集_《C++ Primer 第四版》

    在C语言中要对一个整数的某一个位进行操作需要用到很多的技巧.这种情况在C++里面通过标准库提供的一个抽象数据类型 bitset得到了改善. 一.标准库bitset类型 1.bitset的作用 bits ...

  3. C++_系列自学课程_第_3_课_变量和基本类型_《C++ Primer 第四版》

    最近复习C++相关内容,决定在这里记录自己复习的过程. 以前写过部分文字,但是没有坚持连续写,因此学完后 基本又忘光啦,主要是没有实践,这一次决定自学完后,在这里在复习一遍增强自己的记忆和理解程度. ...

  4. C++_系列自学课程_第_12_课_结构体

    #include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...

  5. C++_系列自学课程_第_12_课_语句_《C++ Primer 第四版》

    前面的文章说完了表达式和类型转换的部分内容,在我参考的书里面,接下来讨论的是各种语句,包括:顺序语句.声明语句.复合语句(块语句).语句作用域 .if语句.while语句.for语句.do...whi ...

  6. C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》

    上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换. 一.隐式类型转换 在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符 ...

  7. C++_系列自学课程_第_10_课_表达式_《C++ Primer 第四版》

    程序设计语言中大部分程序都在进行表达式的求值操作, 例如求两个数的和,求一个表达式的逻辑结果,或者通过输入输出表达式语句进行输入和输出. 这里我们对表达式进行讨论. 一.表达式 1.表达式 表达式由一 ...

  8. C++_系列自学课程_第_9_课_C语言风格字符串_《C++ Primer 第四版》

    前面说了写关于数组和指针的内容,这次在这里讨论一下字符串,讨论一下C语言风格的字符串. 在C语言里面我们利用字符数组来对字符串进行处理, 在C++里面我们前面说过一种类类型string可以对字符串进行 ...

  9. C++_系列自学课程_第_8_课_指针和引用_《C++ Primer 第四版》

    C语言最富有迷幻色彩的部分当属指针部分,无论是指针的定义还是指针的意义都可算是C语言中最复杂的内容.指针不但提供给了程序员直接操作硬件部分的操作接口,还提供给了程序员更多灵活的用法.C++继承这一高效 ...

随机推荐

  1. 关于分工的思考 (Thoughts on Division of Labor)

    Did you ever have the feeling that adding people doesn't help in software development? Did you ever ...

  2. Azure PowerShell (7) 使用CSV文件批量设置Virtual Machine Endpoint

    <Windows Azure Platform 系列文章目录> 请注意: - Azure不支持增加Endpoint Range - 最多可以增加Endpoint数量为150 http:// ...

  3. 每天一个linux命令(46):vmstat命令

    vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存.进程.CPU活动进行监控.他是对系统的整体情况进行统计,不足之处是无法对某个进程进行深 ...

  4. CI Weekly #4 | 不同规模的团队,如何做好持续集成?

    CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...

  5. angular中的compile和link函数

    angular中的compile和link函数 前言 这篇文章,我们将通过一个实例来了解 Angular 的 directives (指令)是如何处理的.Angular 是如何在 HTML 中找到这些 ...

  6. SQL Server Audit监控触发器状态

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 注意事项(Attention) 疑问(Questions) 参 ...

  7. jQuery源码分析系列:Callback深入

    关于Callbacks http://www.cnblogs.com/aaronjs/p/3342344.html $.Callbacks()的内部提供了jQuery的$.ajax() 和 $.Def ...

  8. 【原创】开源Math.NET基础数学类库使用(17)C#计算矩阵条件数

                   本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新  开源Math.NET基础数学类库使用总目录:[目录]开源Math.NET基础数学类库使用总目录 上个月 ...

  9. Java 8新特性-1 函数式接口

    Java 8 引入的一个核心概念是函数式接口(Functional Interfaces). 通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行. 如果一个接口定义个唯一一个抽象方法,那么这 ...

  10. 在Windows中安装NodeJS的正确姿势

    NodeJS已经非常流行了,而且可以预见他将继续受到追捧.这确实是一个不错的创举,想想看他现在能做什么吧 1.服务器程序(典型的就是用来做网站或者restful服务,主打就是多线程,非阻塞,最后,一个 ...