一、前言
vector 和 array 的不同之处在于:array 实现的是动态数组(容量固定的数组),而 vector 实现的是一个动静数组。
vector 容器以类模板 vector<T>(T 示意存储元素的类型)的模式定义在 <vector> 头文件中,并位于 std 命名空间中。因而,在创立该容器之前,代码中需蕴含如下内容:
#include <vector>
using namespace std;
阐明:std 命名空间也可在应用 vector 容器时额定注明,如:
std::vector<double> values;
二、创立 vector 的形式
①std::vector<int> vecInt;
②std::vector<int> vecInt {1,5,23,45,87};
③std::vector<int> vecInt(10);
④std::vector<int> vecInt(10, 4);
①形式创立一个空的 vector 容器,因为容器中没有元素,所以没有调配空间,当用户增加元素时,vector 会主动分配内存空间。如果创立好的 vector 容器的容量有余,可通过 reserve()减少容器的容量。须要留神的是:
调用 reserve() 不会影响已存储的元素,也不会生成任何元素,即 vecInt 容器内此时依然没有任何元素;如果调用 reserve() 来减少容器容量,之前创立好的任何迭代器(例如开始迭代器和完结迭代器)都可能会生效,因为为了减少容器的容量,vector<T> ** 容器的元素可能曾经被复制或移到了新的内存地址 **。
②形式创立一个蕴含有 5 个元素的 vector 容器
③形式创立一个有 10 个元素、默认初始值为 0 的 vector 容器
④形式创立一个有 10 个元素、指定初始值为 4 的 vector 容器
圆括号 () 和大括号 {} 是有区别的,前者示意元素的个数,而后者则示意 vector 容器中的元素值。
三、成员函数
成员函数 | 性能 |
---|---|
begin() | 返回指向容器中第一个元素的迭代器 |
end() | 返回指向容器最初一个元素所在位置后一个地位的迭代器,通常和 begin() 联合应用 |
rbegin() | 返回指向最初一个元素的迭代器 |
rend() | 返回指向第一个元素所在位置前一个地位的迭代器 |
cbegin() | 和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素 |
cend() | 和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素 |
crbegin() | 和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素 |
crend() | 和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素 |
size() | 返回理论元素个数 |
max_size() | 返回元素个数的最大值,个别是 232-1,所以咱们很少会用到这个函数 |
resize() | 扭转理论元素的个数 |
capacity() | 返回以后容量 |
empty() | 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false |
reserve() | 减少容器的容量 |
shrink _to_fit() | 将内存缩小到等于以后元素理论所应用的大小 |
operator[] | 重载了 [] 运算符,能够向拜访数组中元素那样,通过下标即可拜访甚至批改 vector 容器中的元素 |
at() | 应用通过边界查看的索引拜访元素 |
front() | 返回第一个元素的援用 |
back() | 返回最初一个元素的援用 |
data() | 返回指向容器中第一个元素的指针 |
assign() | 用新元素替换原有内容 |
push_back() | 在序列的尾部增加一个元素 |
pop_back() | 移出序列尾部的元素 |
insert() | 在指定的地位插入一个或多个元素 |
erase() | 移出一个元素或一段元素 |
clear() | clear() |
swap() | 替换两个容器的所有元素 |
emplace() | 在指定的地位间接生成一个元素 |
emplace_back() | 在序列尾部生成一个元素 |
std::swap(x , y) | 非成员函数,替换数据 |
四、迭代器的用法
vector 的迭代器成员函数和 array 根本是一样的,如下:
begin()
end()
rbegin()
rend()
cbegin()
cend()
crbegin()
crend()
具体性能图示与 https://segmentfault.com/a/11…
1、vector 迭代器的独特之处
vector 容器能够随着存储元素的减少,自行申请更多的存储空间。因而,在创立 vector 对象时,咱们能够间接创立一个空的 vector 容器,并不会影响后续应用该容器。
vector 容器在申请更多内存后,再次应用之前的迭代器,可能会导致解体,因为 vector 容器在减少容量之后,首个元素的存储地址产生了变动,这个时候再应用之前创立的迭代器显然是谬误的,这个时候须要从新初始化迭代器。
五、拜访 vector 容器元素的形式
1、下标形式[]
相似 C ++ 中数组的拜访形式,vector 容器的索引是从 0 开始的,和数组一样。须要保障下标 n 的值不会超过容器的容量,否则会产生拜访越界的谬误。
2、at()
当传给 at()的索引值越界时,会抛出异样
3、遍历 vector 容器元素
依据 size()获取 vector 容器的大小,遍历容器中的元素即可
留神:不能应用 capacity(),因为它返回的是 vector 容器的容量而不是理论存储元素的个数。
六、vector 容器增加元素
向 vector 容器中增加元素的惟一形式就是应用它的成员函数
1、push_back()
在 vector 容器尾部增加一个元素
2、emplace_back()
C++11 新增的,性能和 push_back()雷同。
既然性能雷同,为什么要减少一个 emplace_back()呢?
首先咱们理解一下 emplace_back() 和 push_back() 的区别:底层实现的机制不同。push_back() 向容器尾部增加元素时,首先会创立这个元素,而后再将这个元素拷贝或者挪动到容器中(如果是拷贝的话,预先会自行销毁先前创立的这个元素);而 emplace_back() 在实现时,则是间接在容器尾部创立这个元素,省去了拷贝或挪动元素的过程,因而 emplace_back()的执行效率比 push_back()高。
七、vector 插入元素
1、insert()
在 vector 容器的指定地位插入一个或多个元素。该函数的语法格局有多种,如下:
格局 | 阐明 |
---|---|
iterator insert(pos,elem) | 在迭代器 pos 指定的地位之前插入一个新元素 elem,并返回示意新插入元素地位的迭代器 |
iterator insert(pos,n,elem) | 在迭代器 pos 指定的地位之前插入 n 个元素 elem,并返回示意第一个新插入元素地位的迭代器 |
iterator insert(pos,first,last) | 在迭代器 pos 指定的地位之前,插入其余容器(不仅限于 vector)中位于 [first,last) 区域的所有元素,并返回示意第一个新插入元素地位的迭代器 |
iterator insert(pos,initlist) | 在迭代器 pos 指定的地位之前,插入初始化列表(用大括号 {} 括起来的多个元素,两头有逗号隔开)中所有的元素,并返回示意第一个新插入元素地位的迭代器 |
2、emplace()
C++ 11 中新增的成员函数,用于在 vector 容器指定地位之前插入 一个 新的元素。
iterator emplace (const_iterator pos, args...);
pos 为指定插入地位的迭代器;args… 示意与新插入元素的构造函数绝对应的多个参数;该函数会返回示意新插入元素地位的迭代器。
留神:
①当拷贝构造函数和挪动构造函数同时存在时,insert() 会优先调用挪动构造函数。
②理论中,emplace() 的运行效率比 insert()高。emplace() 在插入元素时,是在容器的指定地位间接结构元素,而不是先独自生成,再将其复制(或挪动)到容器中。
八、vector 删除元素的几种形式
如下:
函数 | 性能 |
---|---|
pop_back() | 删除 vector 容器中最初一个元素,该容器的大小(size)会减 1,但容量(capacity)不会产生扭转 |
erase(pos) | 删除 vector 容器中 pos 迭代器指定地位处的元素,并返回指向被删除元素下一个地位元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会产生扭转 |
swap(beg)、pop_back() | 先调用 swap() 函数替换要删除的指标元素和容器最初一个元素的地位,而后应用 pop_back() 删除该指标元素 |
erase(beg,end) | 删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个地位元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会产生扭转 |
remove() | 删除容器中所有和指定元素值相等的元素,并返回指向最初一个元素下一个地位的迭代器。值得一提的是,调用该函数不会扭转容器的大小和容量 |
clear() | 删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会扭转 vector 的大小(变为 0),但不是扭转其容量 |
九、实例
1、拜访 vector 容器中的元素
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// 初始化 vector
std::vector<int> vecInt;
std::vector<int> vecInt2{3,8,9,6,7,10};
std::vector<int> vecInt3(10);
std::vector<int> vecInt4(20, 4);
for (size_t i = 0; i < vecInt.size(); i++)
{std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "vecInt size:" << vecInt.size() << "capacity:" << vecInt.capacity() << std::endl;
for (size_t i = 0; i < vecInt2.size(); i++)
{std::cout << "vecInt2[" << i << "]=" << vecInt2[i] << std::endl;
}
std::cout << "vecInt2 size:" << vecInt2.size() << "capacity:" << vecInt2.capacity() << std::endl;
for (size_t i = 0; i < vecInt3.size(); i++)
{std::cout << "vecInt3[" << i << "]=" << vecInt3[i] << std::endl;
}
std::cout << "vecInt3 size:" << vecInt3.size() << "capacity:" << vecInt3.capacity() << std::endl;
for (size_t i = 0; i < vecInt4.size(); i++)
{std::cout << "vecInt4[" << i << "]=" << vecInt4[i] << std::endl;
}
std::cout << "vecInt4 size:" << vecInt4.size() << "capacity:" << vecInt4.capacity() << std::endl;
system("pause");
return 0;
}
后果如下:
2、vector 容器迭代器的应用
// 初始化 vector
std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};
//begin、end
int i = 0;
std::vector<int>::iterator vecIter = vecInt.begin();
for (; vecIter != vecInt.end(); vecIter++)
{std::cout << "begin and end test: vecInt[" << i++ << "]=" << *vecIter << std::endl;
}
//rbegin、rend
i = 0;
std::vector<int>::reverse_iterator vecIterR = vecInt.rbegin();
for (; vecIterR != vecInt.rend(); vecIterR++)
{std::cout << "rbegin and rend test: vecInt[" << i++ << "]=" << *vecIterR << std::endl;
}
//cbegin、cend
i = 0;
std::vector<int>::const_iterator vecIterC = vecInt.cbegin();
for (; vecIterC != vecInt.cend(); vecIterC++)
{std::cout << "cbegin and cend test: vecInt[" << i++ << "]=" << *vecIterC << std::endl;
}
//crbegin、crend
i = 0;
std::vector<int>::const_reverse_iterator vecIterCR = vecInt.crbegin();
for (; vecIterCR != vecInt.crend(); vecIterCR++)
{std::cout << "crbegin and crend test: vecInt[" << i++ << "]=" << *vecIterCR << std::endl;
}
后果如下:
3、拜访 vector 容器元素
// 初始化 vector
std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};
// 下标形式
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
//at()形式
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "vecInt[" << i << "]=" << vecInt.at(i) << std::endl;
}
// 迭代器形式
int i = 0;
std::vector<int>::iterator vecIter = vecInt.begin();
for (; vecIter < vecInt.end(); vecIter++)
{std::cout << "iterator vecInt[" << i++ << "]=" << *vecIter << std::endl;
}
后果如下:
4、往 vector 中插入元素
// 初始化 vector
std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};
// 增加元素
vecInt.push_back(4301);
vecInt.emplace_back(910);
// 下标形式
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "push_back and emplace_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
//insert
vecInt.insert(vecInt.begin(), 72);
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "insert begin vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
vecInt.insert(vecInt.end(), 189);
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "insert end vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::array<int, 2> arrayInt{13,15};
vecInt.insert(vecInt.end(), arrayInt.begin(), arrayInt.end());
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "insert array vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
vecInt.insert(vecInt.end(), {73,98,49});
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "insert array2 vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
后果如下:
5、删除 vector 容器中的元素
// 初始化 vector
std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301,201,701,623,82,201,2909};
vecInt.pop_back();
//
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "pop_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "pop_back vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
//erase
vecInt.erase(vecInt.begin() + 3);
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "erase vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "erase vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
//swap
swap(*(std::begin(vecInt) + 1), *(std::end(vecInt) - 1));
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "after swap vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "after swap vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
vecInt.pop_back();
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "after swap rest vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
//erase 指定范畴
vecInt.erase(vecInt.begin() + 2, vecInt.end() - 5);
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "erase appoint vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
//remove
std::remove(vecInt.begin(), vecInt.end(), 3);
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "after remove vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "remove vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
//clear
vecInt.clear();
for (int i = 0; i < vecInt.size(); i++)
{std::cout << "clear vecInt[" << i << "]=" << vecInt[i] << std::endl;
}
std::cout << "clear vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
后果如下:
阐明:
pop_back:执行后删除了最初一个元素,容器大小 -1,容量不变;
erase:执行后,会返回一个指向删除元素所在位置下一个地位的迭代器,erase 在删除元素时,会将删除地位后续的元素陆续前移,并将容器的大小减 -1;erase 也能够删除指定区域的元素,会返回指向此区域之后一个地位的迭代器;
remove:删除容器中和指定元素值雷同的所有元素,在对容器执行完 remove() 函数之后,因为该函数并没有扭转容器原来的大小和容量,因而借助 remove() 返回的迭代器实现正确的遍历 。
remove() 的实现原理是:在遍历容器中的元素时,一旦遇到指标元素,就做上标记,而后持续遍历,直到找到一个非指标元素,即用此元素将最先做标记的地位笼罩掉,同时将此非指标元素所在的地位也做上标记,期待找到新的非指标元素将其笼罩。通过 remove() 函数删除掉 demo 容器中的多个指定元素,该容器的大小和容量都没有扭转,其残余地位还保留了之前存储的元素,此时能够应用 erase 清理无用的数据:
vecInt.erase(iter, vecInt.end());
倡议 :remove() 用于删除容器中指定元素后,可应用 erase() 成员函数清理无用数据。
clear:清理容器中所有的元素