C++中的vector容器对象学习笔记

 更新时间:2020年4月25日 17:35  点击:1417

C++中数组很坑,有没有类似Python中list的数据类型呢?类似的就是vector! vector 是同一种类型的对象的集合 ,每个对象都有一个对应的整数索引值。和 string 对象一样,标准库将负责管理与存储元素相关的内存。 我们把 vector 称为容器,是因为它可以包含其他对象 。 一个容器中的所有对象都必须是同一种类型的 。

vector对象的定义和初始化

同样的,使用前,导入头文件#include <vector> 可以使用using声明:using std::vector;

vector 是一个类模板(class template)。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。因此,我们可以定义保存 string 对象的 vector,或保存 int 值的 vector,又或是保存自定义的类类型对象(如 Sales_items 对象)的 vector。

声明从类模板产生的某种类型的对象,需要提供附加信息,信息的种类取决于模板。 以 vector 为例,必须说明 vector 保存何种对象的类型,通过将类型放在类型放在类模板名称后面的尖括号中来指定类型:

vector<T> v1; 保存类型为 T 对象。默认构造函数 v1 为空。
vector<T> v2(v1); v2 是 v1 的一个副本。
vector<T> v3(n, i); v3 包含 n 个值为 i 的元素。
vector<T> v4(n); v4 含有值初始化的元素的 n 个副本。

【注意:1、若要创建非空的 vector 对象,必须给出初始化元素的值;2、当把一个 vector 对象复制到另一个 vector 对象时,新复制的 vector 中每一个元素都初始化为原 vectors 中相应元素的副本。但这两个 vector 对象必须保存同一种元素类型;3、可以用元素个数和元素值对 vector 对象进行初始化。构造函数用元素个数来决定 vector 对象保存元素的

个数,元素值指定每个元素的初始值】

vector对象动态增长 :

vector 对象(以及其他标准库容器对象)的重要属性就在于 可以在运行时高效地添加元素。

【注意:因为

vector 增长的效率高

,在元素值已知的情况下,最好是动态地添加元素。】
值初始化:

如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行,具体值为何,取决于存储在vector 中元素的数据类型。

如果为int型数据,那么标准库将用 0 值创建元素初始化式;

如果 vector 保存的是含有构造函数的类类型(如 string)的元素,标准库将用该类型的默认构造函数创建元素初始化式;

元素类型可能是没有定义任何构造函数的类类型。这种情况下,标准库仍产生一个带初始值的对象,这个对象的每个成员进行了值初始化。

#include <iostream>
#include <string>
#include <vector>

int main()
{
 std::vector<int> a;
 std::vector<int> b(a);
 std::vector<int> c(10, 23);
 std::vector<std::string> svec(10, "null");
 std::vector<std::string> svec2(10, "hi!");
 std::vector<std::string> svec3(10);
 return 0;
}

注意,没有=号!
vector对象操作方法

和string类似!
.v.empty()

Returns true if v is empty; otherwise returns false如果 v 为空,则返回 true,否则返回 false。

.v.size()

Returns number of elements in v返回 v 中元素的个数。

【注意:1、返回相应 vector 类定义的size_type 的值,和string类似。2、使用 size_type 类型时,必须指出该类型是在哪里定义的。vector 类型总是包括总是

包括 vector 的元素类型 vector<int>::size_type

v.push_back(t)

Adds element with value t to end of v在 v 的末尾增加一个值为 t 的元素。以下为例子:

#include <iostream>
#include <string>
#include <cctype>
#include <vector>

int main()
{
 // read words from the standard input and store them as elements in a vector
 std::string word;
 std::vector<std::string> text; // empty vector
 while (std::cin >> word) 
 {
 text.push_back(word); // append word to text
 for(std::vector<int>::size_type ix =0; ix != text.size(); ++ix)
  std::cout<<"Now text["<<ix<< "]is: "<<text[ix]<<std::endl;
 }
 return 0;
}

结果为:

Hello
Now text[0]is: Hello
world!
Now text[0]is: Hello
Now text[1]is: world!


注意:
1、不可以直接输出vector对象! 和list差别太大了。。。

2、下标操作可以改变已有元素:例如上例,可以在最后加上:text[0] = "elements";

3、当然和list一样,肯定不能text[100] = "elements";在Python中这样操作list回报下标越界, C++中编译不会报错,运行自动退出!【 数组操作时这个会坑死你,不会报错,不会退出!理所当然,缓冲区溢出了,黑客们太喜欢了! 】

4、由于动态增长, 不能先测试长度 ,而是循环中动态测试!否则会出现莫名其妙的BUG!有人会担心效率?别担心!代价很小【内联函数】。

v[n]

Returns element at position n in v返回 v 中位置为 n 的元素。

(1)v1 = v2[/code]

Replaces elements in v1 by a copy of elements in v2把 v1 的元素替换为 v2 中元素的副本。

(2)v1 == v2[/code]

Returns true if v1 and v2 are equal如果 v1 与 v2 相等,则返回 true。

(3)!=, <, <=,>, and >=

Have their normal meanings保持这些操作符惯有的含义。

一个简单的例子

读入一段文本到 vector 对象,每个单词存储为 vector 中的一个元素。把vector 对象中每个单词转化为大写字母。输出 vector 对象中转化后的元素,每八个单词为一行输出。

假设文本为:in the vector. transform each word into uppercase letters. Print the transformed elements from the vector, printing eight words to a line.

#include <iostream>
#include <string>
#include <vector>

std::string deal_word(std::string word)
{
 std::string WORD; // 创建空字符串
 for(std::string::size_type ix =0; ix != word.size(); ++ix)
 {
 if (not ispunct(word[ix]))
 {
  WORD += toupper(word[ix]); //连接非标点字符到字符串
 }
 }
 return WORD;
}

int main()
{
 std::string word; // 缓存输入的单词
 std::vector<std::string> text; // empty vector
 std::cout<<"Please input the text:"<<std::endl; //提示输入
 while (std::cin >> word and word != "INPUTOVER") // INPUTOVER 用于标示输入结束,也可以ctrl + z停止输入 
 {
 word = deal_word(word); // 单词处理
 text.push_back(word); // append word to text
 }
 for(std::vector<int>::size_type ix =0, j = 0; ix != text.size(); ++ix, ++j)
 {
 if (j==8) // 8个单词一行
 {
  std::cout<<std::endl; //换行
  j = 0; //重新计数
 }
  std::cout<<text[ix]<<" "; //加空格!
 }
 return 0;
}

结果为:

Please input the text:
in the vector. transform each word into uppercase letters. Print the transformed elements from the vector, printing eight words to a line. INPUTOVER
IN THE VECTOR TRANSFORM EACH WORD INTO UPPERCASE 
LETTERS PRINT THE TRANSFORMED ELEMENTS FROM THE VECTOR 
PRINTING EIGHT WORDS TO A LINE

vector.resize 与 vector.reserve

reserve是容器预留空间,但并不真正创建元素对象,在创建对象之前,不能引用容器内的元素,因此当加入新的元素时,需要用push_back()/insert()函数。
resize是改变容器的大小,并且创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。
再者,两个函数的形式是有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。下面是这两个函数使用例子:

vector<int> myVec;

myVec.reserve( 100 );  // 新元素还没有构造,

       // 此时不能用[]访问元素

for (int i = 0; i < 100; i++ )

...{

  myVec.push_back( i ); //新元素这时才构造

}

myVec.resize( 102 );  // 用元素的默认构造函数构造了两个新的元素

myVec[100] = 1;   //直接操作新元素

myVec[101] = 2;

初次接触这两个接口也许会混淆,其实接口的命名就是对功能的绝佳描述,resize就是重新分配大小,reserve就是预留一定的空间。这两个接口即存在差别,也有共同点。下面就它们的细节进行分析。
为实现resize的语义,resize接口做了两个保证:
一是保证区间[0, new_size)范围内数据有效,如果下标index在此区间内,vector[indext]是合法的。
二是保证区间[0, new_size)范围以外数据无效,如果下标index在区间外,vector[indext]是非法的。
reserve只是保证vector的空间大小(capacity)最少达到它的参数所指定的大小n。在区间[0, n)范围内,如果下标是index,vector[index]这种访问有可能是合法的,也有可能是非法的,视具体情况而定。
resize和reserve接口的共同点是它们都保证了vector的空间大小(capacity)最少达到它的参数所指定的大小。
因两接口的源代码相当精简,以至于可以在这里贴上它们:

void resize(size_type new_size) 
{ 
 resize(new_size, T()); 
}
void resize(size_type new_size, const T& x) 
{
 if (new_size < size()) 
  erase(begin() + new_size, end()); // erase区间范围以外的数据,确保区间以外的数据无效
 else
  insert(end(), new_size - size(), x); // 填补区间范围内空缺的数据,确保区间内的数据有效
} 

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 基于C++中常见编译错误的总结详解

    本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • c++优先队列(priority_queue)用法详解

    这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25