深入了解 C++ 中向量类的用法和功能

 2024-02-07 05:01:47  阅读 0

//
template < class T, class Alloc = allocator > class vector;

向量 () 是一个顺序容器 ( ),它封装了动态大小的数组。与任何其他类型的容器一样,它可以容纳所有类型的对象。简单地说,向量是一个可以容纳任何类型的动态数组。类

提供了内置数组的替代表示形式,与类一样,类是标准 C++ 引入的标准库的一部分,为了使用它们,我们必须包含相关的头文件:

#include 

电容特性:

1. 顺序序列顺序

容器中的元素按严格的线性顺序排序。可以通过其在序列中的位置访问相应的元素。

2. 动态阵列

支持快速、直接地访问序列中的任何元素,甚至通过指针算术。允许在序列末尾相对快速地添加/删除元素。

3. 内存分配器感知 (-aware)。

容器使用内存分配器对象来动态处理其存储要求。

用:

有两种不同的使用形式,即所谓的数组习惯和 STL 习惯。

1. 数组成语

1. 定义已知长度:

vector< int > ivec( 10 ); //类似数组定义int ia[ 10 ];

可以通过 ivec[index ] 访问元素。

c vector 删除元素_删除元素平均移动次数_删除元素c语言

使用 if ( ivec.empty() ) ) to

确定它是否为空,并确定 ivec.size() 以确定元素的数量。

2.元素初始化为与其类型相关的默认值:算术和指针类型的默认值为0,对于类类型,可以通过调用该类型的默认构造函数来获取默认值,我们还可以为每个要初始化的元素提供显式的初始值, 例如

< int > ivec( 10, -1 );

定义了 ivec,它包含 int 类型的 10 个元素,每个元素都初始化为 -1对于内置数组,

我们可以将数组的元素显式初始化为一组常量值,例如:

int ia[ 6 ] = { -2, -1, 0, 1, 2, 1024 };

我们不能以同样的方式显式初始化,但可以通过指定要初始化的数组的起始地址和数组最后一个元素的下一个位置来初始化为现有数组的全部或部分,例如:

// 把 ia 的 6 个元素拷贝到 ivec 中 
vector< int > ivec( ia, ia+6 ); 

传递给 ivec 的两个指针标记用于初始化对象的值范围,第二个指针始终指向要复制的最后一个元素的下一个位置,标记的元素范围也可以是数组的子集,例如:

// 拷贝 3 个元素 ia[2], ia[3], ia[4] 
vector< int > ivec( &ia[ 2 ], &ia[ 5 ] );

3. 与内置数组不同,它们可以由另一个人初始化或分配给另一个人,例如

vector< string > svec; 
void init_and_assign() 
{ 
  // 用另一个 vector 初始化一个 vector 
  vector< string > user_names( svec ); 
  // ... 
 
  // 把一个 vector 拷贝给另一个 vector 
  svec = user_names; 
}

2. STL成语

在 STL9 中的惯用用法是完全不同的。我们没有定义一个已知的大小,而是定义一个空的

< >文本;

删除元素平均移动次数_删除元素c语言_c vector 删除元素

1. 我们将元素插入元素而不是索引元素,并为元素赋值,例如 (),即在 while 循环之后插入一个元素,该循环从标准输入中读取字符串序列并一次插入一个字符串

string word; 
while ( cin >> word ) { 
text.push_back( word ); 
// ... 
}

虽然我们仍然可以使用下标运算符来迭代访问元素

cout << "words read are: \n"; 
 
for ( int ix = 0; ix < text.size(); ++ix ) 
   cout << text[ ix ] << ' '; 
 
cout << endl; 

但是,更典型的是在操作集中使用 begin() 和 end() 返回的迭代器

右:

cout << "words read are: \n"; 
 
for ( vector::iterator it = text.begin(); 
  it != text.end(); ++it ) 
      cout << *it << ' '; 
 
cout << endl 

是标准库中用作指针的类

复制代码 代码如下:

*它;

取消引用迭代器并访问它指向的实际对象

复制代码 代码如下:

++它;

将迭代器向前移动,使其指向下一个元素

2.注意不要混淆这两种惯用用法,例如,下面的定义

vector< int > ivec; 

定义一个空的重写这样的语句

ivec[ 0 ] = 1024; 

这是错误的,因为 ivec 还没有第一个元素,我们只能索引 size() 操作中已经存在的元素数量。

3. 同样,当我们定义一个给定的大小时,例如:

vector ia( 10 ); 

很明显,任何一个插入都会增加而不是覆盖现有元素的大小,但以下错误在初学者中并不少见

const int size = 7; 
int ia[ size ] = { 0, 1, 1, 2, 3, 5, 8 }; 
vector< int > ivec( size ); 
 
for ( int ix = 0; ix < size; ++ix ) 
  ivec.push_back( ia[ ix ]); 

在末尾

程序 IVEC 有 14 个元素,IA 的元素是从第 8 个元素插入的。

更深入的理解

在向量中,所有元素都是连续存储的。也就是说,单个元素不仅可以通过迭代器 () 访问,还可以通过指向元素的指针和偏移量来访问。这也意味着,当指向向量元素的指针传递给任意函数时,可以将指针直接视为指向数组中的元素。

向量内部的存储调整是自动处理的,并根据需要进行缩放或压缩。通常,向量将比静态数组 ( ) 占用更多的存储空间,因为额外的内存将被未来的增长所使用。因此,向量在插入元素时不需要过于频繁地重新分配 ()内存。可以通过函数查询当前最大容量。可以通过调用 () 函数将多余的内存返回给操作系统。

在向量对象中增加序列的长度时,如果超过当前存储容量限制,则会发生内存重新分配(即,在内部重新分配数组,并按顺序逐个复制元素。其他插入和删除将修改序列中某些元素的内存地址。在所有这些情况下,指向序列修改部分的迭代器或引用都将失效。当未发生内存重新分配时,只有迭代器或对指向插入点或删除点之前的元素的引用仍然有效。

标准库可以执行不同的增长策略,以通过重新分配来平衡内存使用和性能消耗。然而,无论哪种情况,重新分配的内存的大小都必须呈指数增长,以便在向量末尾插入元素所需的时间复杂度可以摊销到一个恒定值 () 作为一个整体。

就性能而言,内存重新分配是一项代价高昂的操作。如果在使用向量之前知道元素的数量,则可以消除内存重新分配 ()。

向量支持在序列末尾插入和删除元素,耗时恒定。在向量中间插入或删除元素需要线性时间。当它只涉及在序列的开头或结尾插入和删除元素时,std::d eque 容器的性能会高得多。当涉及到插入和删除序列中的任何位置时,std::list 容器的性能会高得多。

常见操作的算法复杂度(取决于性能)如下:

标签: 元素 数组 操作

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码