赞
踩
STL vector 表示的是对象的集合,其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问对象。因为 vector“容纳着”其他对象,所以它也常被称作容器(container)。
vector 数据结构和数组非常相似,也称为单端数组,即只允许向数组的一头进行输入输出操作,符合前闭后开原则。
注意:vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,例如vector。
数组是静态空间,而vector是可以动态扩展的,也可以叫做可变长数组。
动态扩展:并不是在原空间后续接空间,而是重新创建一个更大的新空间,复制到新空间上,然后释放原空间。
迭代器是一种用于访问容器元素的对象,类似于指针,可以通过迭代器来遍历容器中的元素。
这里可以加深对迭代器的了解:c++ STL 常用迭代器以及使用
void printVector(vector<int>& v) {
for (vector<int>::iterator it = v.begin(); it < v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
void test01(){
//默认构造 无参构造
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << "v1 = ";
printVector(v1);
// 拷贝构造
vector<int> v2(v1);
cout << "v2 = ";
printVector(v2);
// operator= 赋值
vector<int>v3;
v3 = v1;
cout << "v3 = ";
printVector(v3);
// assign 函数赋值
vector<int>v4;
v4.assign(10, 100);
cout << "v4 = ";
printVector(v4);
}
关键概念:vector对象能高效增长:
C++标准要求 vector 应该能在运行时高效快速地添加元素。
既然 vector 对象能高效地增长,那么在定义 vector 对象的时候设定其大小也就没什么必要了,事实上如果这么做性能可能更差。只有一种例外情况,就是所有 (all) 元素的值都一样。一旦元素的值有所不同,更有效的办法是先定义一个空的 vector 对象,再在运行时向其中添加具体值。
开始的时候创建空的 vector 对象,在运行时再动态添加元素,这一做法与C语言及其他大多数语言中内置数组类型的用法不同。特别是如果用惯了C或者 Java,可以预计在创建vector 对象时顺便指定其容量是最好的。然而事实上,通常的情况是恰恰相反。`
void test02() {
vector<int>v; //默认构造
v.assign(10, 100);
if (v.empty()) //判断是否为空
{
cout << "v为空" << endl;
}
else {
cout << "v不为空" << endl;
}
cout << "v容量为:" << v.capacity() << endl; // 10
cout << "v大小为:" << v.size() << endl; // 10
//resize()两种用法
v.resize(3); // 指定容器数据大小为 size = 3
cout << "v容量为:" << v.capacity() << endl; // 10
cout << "v大小为:" << v.size() << endl; // 3
v.resize(10, 100); //指定容器的大小为10,数据为100
cout << "v容量为:" << v.capacity() << endl; // 10
cout << "v大小为:" << v.size() << endl; // 10
printVector(v);
}
函数原型:
// 在指定位置 pos 插入多个相同的元素,共插入 count 个,并使用给定的 value 初始化这些元素。返回一个指向第一个插入元素的迭代器。
iterator insert(const_iterator pos, size_type count, const T& value);
// 在指定位置 pos 插入一个元素,并使用给定的 value 初始化该元素。返回一个指向插入元素的迭代器。
iterator insert(const_iterator pos, const T& value);
// 从容器中删除位于指定位置 pos 的元素,并返回一个指向被删除元素后一个元素的迭代器。
iterator erase(const_iterator pos);
// 从容器中删除范围 [first, last) 内的所有元素,并返回一个指向被删除元素后一个元素的迭代器。
iterator erase(const_iterator first, const_iterator last);
代码示例:
void test03(){
vector<int>v;
// 尾插
v.push_back(10);
v.push_back(1);
v.push_back(6);
v.push_back(4);
printVector(v);
// 尾删
v.pop_back();
printVector(v);
// insert(pos,val) 插入操作
v.insert(v.begin(), 2);
printVector(v);
// 批量插,begin()后插入2个元素10
v.insert(v.begin(), 2, 10);
printVector(v);
// erase(pos)删除操作
v.erase(v.begin());
printVector(v);
// erase(first,lasr)清空操作
v.erase(v.begin(), v.end());
printVector(v);
// clear()清空操作
v.clear();
printVector(v);
}
函数原型:
//此函数返回指定位置 pos 处的元素的引用,并进行边界检查。如果 pos 超出了容器范围,会抛出 std::out_of_range 异常。
1. at(size_type pos);
// 此操作符允许通过下标 pos 直接访问容器中的元素,与 at 类似,但不进行边界检查。如果 pos 超出了容器范围,会导致未定义行为。
2. operator[](size_type pos);
// 此函数返回容器中第一个元素的引用。
3. front();
// 函数返回容器中最后一个元素的引用。
4. back();
代码示例:
// 测试
void test04()
{
vector<int>v;
for (int i = 0; i < 10; i++) {
v.push_back(i);
}
printVector(v);
cout << v.at(1) << endl;
cout << v[2] << endl;
cout << v.front() << endl; // 头数据
cout << v.back() << endl; // 尾数据
}
swap() 实际用途:
//互换容器 swap() 以及实际用途
void test05()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int>v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
v1.swap(v2); //互换操作
printVector(v1);
printVector(v2);
cout << "v1容量为:" << v1.capacity() << endl;
cout << "v1大小为:" << v1.size() << endl;
//v1容量为:13 //系统预留大小
//v1大小为:10
//实际用途 收缩多余的内存
v1.resize(3);
cout << "v1容量为:" << v1.capacity() << endl;
cout << "v1大小为:" << v1.size() << endl;
printVector(v1);
//v1容量为:13
//v1大小为:3
//巧用swap来收缩内存
vector<int>(v1).swap(v1);
//vector<int>(v1)匿名对象,利用拷贝构造函数来创建一个新的对象,
//匿名对象(无名)的容量,大小都是v1所用的个数大小,然后swap与原来v1进行互换(根据swap源码:相当于指针的交换)
//执行完这行代码后,系统会将匿名对象回收(匿名对象的特点,当前行执行完,会被系统自动回收)
cout << "v1容量为:" << v1.capacity() << endl;
cout << "v1大小为:" << v1.size() << endl;
printVector(v1);
//v1容量为:3
//v1大小为:3
}
函数原型:
// 调整字符串的长度,使其包含 count 个字符。如果 count 小于当前字符串的长度,则字符串将被截断;如果 count 大于当前字符串的长度,则字符串将被扩展,新的字符用空字符填充。
resize(size_type count);
// 请求字符串的内存容量至少为 new_cap,但不保证实际的容量会达到 new_cap。
reserve(size_type new_cap);
(1)功能区别:
resize()函数
用于调整容器的大小,可以增加或减少容器的元素数量。当增加容器的大小时,会在容器中添加新的元素,并进行默认初始化。当减少容器的大小时,会删除多余的元素。resize()可以用于改变容器的大小并实际操作元素。
reserve()函数
用于向容器预留一定的存储空间,以便在后续的操作中减少重新分配内存的次数。reserve()仅分配内存空间,但不改变容器的大小。它只是预留了一定的容量,可以用于减少动态扩展和内存分配的次数。
(2)参数区别:
resize() 函数
接受一个参数,用于指定容器的目标大小。如果目标大小大于当前容器的大小,则会添加新的元素以扩展容器。如果目标大小小于当前容器的大小,则会删除多余的元素。
reserve() 函数
接受一个参数,用于指定预留的容量大小。这个参数表示容器预留的存储空间,不涉及容器中元素的个数。
(3)容器大小区别:
resize() 函数
会实际改变容器的大小,因此容器的大小会与指定的目标大小相匹配。
reserve() 函数
仅预留容器的存储空间,容器的大小仍然是实际元素的个数。
(4)元素初始化区别:
resize() 函数
在增加容器大小时,会对新添加的元素进行默认初始化。这意味着添加的元素将使用默认构造函数进行初始化。
reserve() 函数
仅预留容器的存储空间,不会初始化预留的空间。因此,在使用 reserve() 预留空间后,容器的元素仍然需要通过其他操作进行初始化。
代码示例:
void test06(){
vector<int>v;
v.reserve(100000); // reserve()仅分配预留的内存空间大小,不改变容器的大小,也没有初始化的操作,可以减少动态扩展的次数
//v.resize(100000); // resize() 函数在增加容器大小时,会对新添加的元素进行默认初始化。默认为0
cout << "v的容量大小:" << v.capacity() << endl;
cout << "v的数据大小:" << v.size() << endl;
//cout << v[0] << endl; // 证明v.reserve()没有初始化v
int num = 0; //记录动态扩展的次数
int* p = NULL; //记录vector的头地址
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
if (p != &v[0]) { //检查地址是否变化
p = &v[0];
num++;
}
}
cout << "动态扩展的次数:" << num << endl; // 次数为:1
}
以上就是vector容器的全部内容。
需要注意的是,虽然 vector 在尾部操作上非常高效,但如果需要在中间或开头进行大量的插入和删除操作,可能需要考虑其他数据结构,如 deque 或 list。
若有错误之处请指出,欢迎在评论区留言!记住多动手编程哦!
欢迎关注
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。