当前位置: 首页 > news >正文

【STL】深入理解 vector 的底层实现思想和使用

vector 是一个顺序表。

根据我们对string的理解和使用我们可以快速使用一些vector的接口(注意:这里不一一介绍所有接口,想理解vector的使用方法的可以看第六点的简洁版)。

一、遍历、修改和尾插

代码示例1:

	vector<int> v;v.push_back(1);//尾插v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (size_t i = 0; i < v.size(); i++){cout << v[i];//[]遍历和修改}cout << endl;

运行结果:

 代码示例2:

	vector<int> v;v.push_back(1);//尾插v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);for (size_t i = 0; i < v.size(); i++){cout << v[i];//[]遍历和修改}cout << endl;vector<int>::iterator it = v.begin();//迭代器遍历for (int i = 0; i < v.size(); i++){cout << *it;it++;}cout << endl;for (auto e : v)//范围for遍历{cout << e;}cout << endl;

运行结果:

二、头插(指定位置插入值)和头删

        跟string不同的是string根据下标来找指定的位置来插入和删除,而vector根据迭代器来找指定的位置进行删除和插入值。

代码示例:

	vector<int> v;v.push_back(1);//尾插v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(6);v.insert(v.begin(), 0);//头插for (size_t i = 0; i < v.size(); i++){cout << v[i];//[]遍历和修改}cout << endl;v.erase(v.begin());//头删for (auto e : v){cout << e;}

运行结果:

 三、构造函数的使用

 常见的构造函数使用示例:

代码示例1:

	vector<int> v = { 1,2,3,4,5,6 };//多个值构造对象//v.insert(v.begin(), 0);//头插for (size_t i = 0; i < v.size(); i++){cout << v[i];//[]遍历和修改}cout << endl;

运行结果:

代码示例2:

	vector<vector<int>> vv(10, vector<int>());//二维数组for (size_t i = 0; i < 10; i++){vv[i].resize(i + 1, 1);}vv[4][3] = 5;// []访问和修改,相当于vv.operator[](4).operator[](3)=5;

注意:关于reverse缩容在string容器他是不确定的,而vector是规定是不缩容。扩容的倍数不同平台是不相同的(vs是1.5倍,Linux是2倍)

四、算法库排序函数:sort()

        默认为升序,对容器的值进行排序,传过去为迭代器。

代码示例:

	vector<int> v = { 3,4,5,5,7,9,2,1 };sort(v.begin(), v.end());//包含头文件#include<algorithm>for (auto e : v){cout << e;}

运行结果:

注意:如果想要进行降序就要传一个仿函数过去:greater<int> gt;

代码示例:

	vector<int> v = { 3,4,5,5,7,9,2,1 };greater<int> gt;sort(v.begin(), v.end(),gt);//包含头文件#include<algorithm>for (auto e : v){cout << e;}
	vector<int> v = { 3,4,5,5,7,9,2,1 };greater<int> gt;//sort(v.begin(), v.end(),gt);//包含头文件#include<algorithm>//也可以传个仿函数的匿名对象sort(v.begin(), v.end(), greater<int>());for (auto e : v){cout << e;}

总结:vector<char>和string不同,string默认后面带个\0,可以插入字符串,而vector没有\0也不能插入字符串只能插入单个字符。find函数vector和list都没有但是算法库支持。

补充知识:

	int i = int(3);//对于内置类型也有匿名对象,进行默认构造int k = int();double j = double();cout << i << endl;cout << k << endl;cout << j << endl;

 运行结果:

五、vector的底层模拟思想

如何看源代码:

1、了解功能:看成员变量

2、抓核心枝干

vector的底层代码模拟:

#pragma once
#include<iostream>
#include<vector>//顺序表
#include<algorithm>
#include<assert.h>
using namespace std;namespace LA
{template<class T>class vector{public:typedef T* iterator;//模板已目前的知识是不能的进行声明和定义分离typedef const T* const_iterator;vector(){_start = nullptr;_finish = nullptr;_end_of_storage = nullptr;}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);//用缺省值来初始化}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);//用缺省值来初始化}}vector(initializer_list<T> il){reserve(il.size());for (auto e:il){push_back(e);}}vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}iterator begin(){return _start;}iterator end(){return _finish;}size_t size()const{return _finish - _start;}size_t capacity()const{return _end_of_storage-_start;}T& operator[](size_t i){assert(i < size());return _start[i];}void resize(size_t n, T val = T()){if (n > size()){reserve(n);while (_finish != _start + n){*_finish = val;_finish++;}}else{_finish = _start + n;//删除数据}}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t old_size = size();if (_start){//size_t old_size = size();//memcpy(tmp, _start, sizeof(T) * old_size);//对内置类型可以,对自定义类型不行,会进行浅拷贝造成两次析构for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = tmp + old_size;_end_of_storage = _start + n;}}void push_back(const T& x){if (_finish == _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();reserve(newcapacity);}*_finish=x;_finish++;}void pop_back(){assert(_finish > _start);_finish--;}iterator insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;//防止迭代器失效:扩容之后pos还是原来那个地址size_t newcapacity = capacity == 0 ? 4 : capacity() * 2;reserve(newcapacity());//扩容要考虑迭代器失效pos = _start + len;//更新pos,防止迭代器失效}iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;it--;}*pos = x;_finish++;return pos;}iterator erase(iterator pos)//使用erase或者insert都要更新迭代器it=v.erase(it);{assert(pos >= _start);assert(pos <= _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;it++;}_finish--;return pos;}private:iterator _start=nullptr;iterator _finish=nullptr;iterator _end_of_storage=nullptr;};
}

六、vector使用方法简洁版

使用之前先包含头文件#include<vector>

1)构造函数

#include<vector>
#include<iostream>
using namespace std;//1)
std::vector<int> v;  // 空的int类型vector//2)
std::vector<int> v(5);          // [0, 0, 0, 0, 0]
std::vector<double> v(3, 3.14);   // [3.14, 3.14, 3.14]//3)
int arr[] = { 1, 2, 3, 4 };
std::vector<int> fromArray(arr, arr + 4);  // [1, 2, 3, 4]std::vector<int> src = { 5, 6, 7 };
std::vector<int> fromVec(src.begin(), src.end());  // [5, 6, 7]//4)
std::vector<int> original = { 10, 20 };
std::vector<int> v(original);  // [10, 20]//5)
std::vector<int> makeVector() {return std::vector<int>{1, 2, 3};
}std::vector<int> moved = makeVector();  // 调用移动构造函数//6)
std::vector<int> nums = { 1, 3, 5, 7 };  // [1, 3, 5, 7]
std::vector<std::string> words{ "hello", "world" };  // ["hello", "world"]

注意:出了移动构造函数、初始化列表构造函数、移动语义是C++11新增的,其他都是C++98的。

2)operator =

//1)
std::vector<int> src = { 1, 2, 3 };
std::vector<int> dst = src; // dst 变为 [1, 2, 3]//2)
std::vector<int> v = { 1,2,3 };
std::vector<int> v2 = { 1,2,4 };
v = v2;//3)
std::vector<int> vec = { 1, 2 };  // 初始化为 [1, 2]
vec = { 3, 4, 5 };  // vec 变为 [3, 4, 5]

3)迭代器

#include <vector>
#include <iostream>int main() {std::vector<int> vec = {1, 2, 3, 4};// 使用普通迭代器(可修改元素也可以读)//1)for (auto it = vec.begin(); it != vec.end(); ++it) {*it *= 2;  // 修改元素}// 使用常量迭代器(只读)//3)for (auto cit = vec.cbegin(); cit != vec.cend(); ++cit) {std::cout << *cit << " ";  // 输出: 2 4 6 8}std::vector<int> vec = {1, 2, 3};// 使用反向迭代器//2)for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {std::cout << *rit << " ";  // 输出: 3 2 1}return 0;
}

4)Capacity

#include <vector>
#include <iostream>int main() {//1)std::vector<int> vec = {1, 2, 3};std::cout << "Size: " << vec.size();    // 输出: 3//4)std::cout << "\nCapacity: " << vec.capacity(); // 可能输出: 3(或更大,取决于实现)//2)std::cout << vec.max_size(); // 返回理论最大值(通常很大)//5)std::vector<int> vec1;std::vector<int> vec2 = {1, 2, 3};std::cout << std::boolalpha;  // 输出 true/false 而非 1/0std::cout << vec1.empty();  // 输出: truestd::cout << vec2.empty();  // 输出: falsevec2.clear();std::cout << vec2.empty();  // 输出: true//7)std::vector<int> vec = { 1, 2 };vec.reserve(200);cout << vec.size() << endl;//2cout << vec.capacity() << endl;//至少是200vec.shrink_to_fit();//可能会失败//有可能会迭代器失效cout << vec.size() << endl;//2cout << vec.capacity() << endl;//2return 0;
}

① n < size        删除元素        影响 size 和有可能影响 capacity

std::vector<int> vec = {1, 2, 3, 4, 5};
vec.resize(3);  // 删除后两个元素
// vec 变为 [1, 2, 3]

注意:这时候也会触发缩容,缩不缩容看平台,不确定,不建议用缩容。

 ② n > capacity>size      扩容         影响 size 和 capacity

	std::vector<int> vec = { 1, 2 };cout << vec.capacity() << endl;//2vec.resize(5);  // 新增3个元素,默认初始化为0// vec 变为 [1, 2, 0, 0, 0]std::vector<int> vec = {1, 2};vec.resize(5, 100);  // 新增3个元素,值为100// vec 变为 [1, 2, 100, 100, 100]

 ① n > capacity >size 扩容,不初始化,影响 capacity 不影响 size

②n < size < capacity 不执行任何操作,不影响 size 和 capacity

	std::vector<int> vec = { 1, 2 };vec.reserve(1);//不执行任何操作cout << vec.size() << endl;//2cout << vec.capacity() << endl;//2vec.reserve(200);cout << vec.size() << endl;//2cout << vec.capacity() << endl;//至少是200

注意:resize 和 reserve 一旦涉及到扩容或者缩容要注意防止迭代器失效。

5)Element access

#include <iostream>
#include <vector>
int main() {//1)std::vector<int> vec = {10, 20, 30};std::cout << vec[1]; // 输出20,读不检查,写抽查//2)std::cout << vec.at(1); // 输出20,会进行边界检查,抛异常//3)std::vector<int> nums = {5, 10, 15};std::cout << nums.front(); // 输出:5num.front() = 85; // 直接修改第一个元素 //{85, 90, 95}//4)std::vector<int> nums = {10, 20, 30};// 访问最后一个元素std::cout << nums.back(); // 输出: 30,后面一旦扩容或者缩容它会失效// 修改最后一个元素nums.back() = 300;std::cout << nums.back(); // 输出: 300//5)std::vector<int> vec = {1, 2, 3};// 获取底层数组指针int* ptr = vec.data();// 通过指针访问元素std::cout << *ptr;       // 输出: 1std::cout << ptr[2];     // 输出: 3// 修改元素*(ptr + 1) = 20;std::cout << vec[1];     // 输出: 20return 0;
}

 6)Modifiers

//1)
std::vector<int> src = { 10, 20, 30 };
std::vector<int> dst;
dst.assign(src.begin(), src.end()); // dst 变为 {10, 20, 30}std::vector<char> vec;
vec.assign(5, 'A'); // vec 变为 {'A', 'A', 'A', 'A', 'A'}std::vector<std::string> words;
words.assign({ "apple", "banana", "cherry" });//2)
std::vector<int> nums;// 添加左值
int x = 10;
nums.push_back(x);         // 拷贝x的值到vector// 直接添加右值(临时对象)
nums.push_back(20);        // 移动语义(若T支持)或拷贝//3)
std::vector<int> nums = { 1, 2, 3 };
nums.pop_back();  // 移除3,nums变为{1, 2}//4)
std::vector<int> nums = { 1, 2, 4, 5 };
// 在位置2(即元素4前)插入3
auto it = nums.insert(nums.begin() + 2, 3);
// nums 现在为 {1, 2, 3, 4, 5std::vector<char> vec = { 'a', 'b', 'c' };
// 在位置1前插入2个'X'
vec.insert(vec.begin() + 1, 2, 'X');
// vec 现在为 {'a', 'X', 'X', 'b', 'c'}std::vector<int> src = { 10, 20, 30 };
std::vector<int> dst = { 5, 15, 25 };
// 将src的所有元素插入到dst的开始位置
dst.insert(dst.begin(), src.begin(), src.end());
// dst 现在为 {10, 20, 30, 5, 15, 25}std::vector<int> vec = { 1, 2 };
vec.insert(vec.end(), { 3, 4, 5 });
// vec 现在为 {1, 2, 3, 4, 5}//5)
std::vector<int> nums = { 1, 2, 3, 4, 5 };
// 移除第3个元素(索引2)
auto it = nums.erase(nums.begin() + 2);
// nums 现在为 {1, 2, 4, 5}std::vector<int> vec = { 10, 20, 30, 40, 50 };
// 移除第2到第4个元素(索引1~3)
auto it = vec.erase(vec.begin() + 1, vec.begin() + 4);
// vec 现在为 {10, 50}std::vector<int> nums = { 1, 2, 3, 4, 5 };
for (auto it = nums.begin(); it != nums.end();) {if (*it % 2 == 0) {it = nums.erase(it);  // erase返回下一个有效迭代器}else {++it;  // 仅在未删除时递增}
}//6)
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 4, 5 };
a.swap(b);  // 或使用非成员函数:swap(a, b);
//a:4,5
//b:1,2,3std::vector<int> small;
small.reserve(100);  // 容量100,大小0
std::vector<int> large(1000, 1);  // 容量1000,大小1000
small.swap(large);
// small: 容量1000,大小1000
// large: 容量100,大小0std::vector<int> vec(1000);
// 方法1:清空元素但不释放内存
vec.clear();  // 容量仍为1000
// 方法2:使用swap释放内存
std::vector<int>().swap(vec);  // 或 vec.swap(std::vector<int>());
// 现在vec的容量和大小均为0std::vector<int> a = { 1, 2 };
std::vector<int> b = { 3, 4 };
auto it_a = a.begin();  // 指向a的第一个元素
a.swap(b);
// it_a现在指向b的第一个元素(值为3)
std::cout << *it_a;  // 输出: 3//7)
std::vector<int> nums = { 1, 2, 3, 4, 5 };
std::cout << "Before clear: size=" << nums.size();  // 输出: 5
std::cout << ", capacity=" << nums.capacity();      // 输出: 5(假设)
nums.clear();
std::cout << "\nAfter clear: size=" << nums.size();   // 输出: 0
std::cout << ", capacity=" << nums.capacity();       // 输出: 5(容量不变)
// 容器为空,但仍可添加元素
nums.push_back(10);
std::cout << "\nAfter push_back: size=" << nums.size();  // 输出: 1class Resource {
public:Resource() { std::cout << "Constructed\n"; }~Resource() { std::cout << "Destructed\n"; }
};
std::vector<Resource> resources(3);  // 构造3次
resources.clear();  // 析构3次,容量不变//8)
struct Person {std::string name;int age;Person(std::string n, int a) : name(std::move(n)), age(a) {std::cout << "Constructed at " << this << "\n";}
};
std::vector<Person> people;
// 使用emplace在尾部原位构造对象
people.emplace(people.end(), "Alice", 25);std::vector<int> vec = { 1, 2, 4 };
// 在位置2(元素4前)构造值为3的元素
vec.emplace(vec.begin() + 2, 3);
// vec 现在为 {1, 2, 3, 4}class MyClass {
public:explicit MyClass(int x) { /* ... */ }
};
std::vector<MyClass> vec;
// emplace直接传递参数,无需隐式转换
vec.emplace(vec.end(), 42);//9)
struct Person {std::string name;int age;// 带参数的构造函数Person(std::string n, int a) : name(std::move(n)), age(a) {std::cout << "Constructed at " << this << "\n";}
};
std::vector<Person> people;
// 使用emplace_back原位构造对象
people.emplace_back("Alice", 25);
// 等效的push_back需要先构造临时对象
people.push_back(Person("Bob", 30));class NonCopyable {
public:NonCopyable(int value) { /* 初始化资源 */ }NonCopyable(const NonCopyable&) = delete;  // 禁用拷贝构造
};
std::vector<NonCopyable> vec;
vec.emplace_back(42);  // 正确:原位构造,无需拷贝/移动class MyClass {
public:explicit MyClass(int value) { /* ... */ }
};
std::vector<MyClass> vec;
vec.emplace_back(42);  // 正确:直接传递构造参数

7)  Allocator

// 创建使用特定分配器的vector
std::vector<int, MyAllocator<int>> vec1;
vec1.push_back(1);
// 使用相同的分配器创建另一个vector
auto alloc = vec1.get_allocator();
std::vector<int, MyAllocator<int>> vec2(alloc);// 假设C函数需要特定方式分配的内存
extern "C" void process_data(int* data, size_t size);
std::vector<int> vec = { 1, 2, 3 };
process_data(vec.data(), vec.size());  // 内存由默认分配器管理class MemoryPoolAllocator {// 内存池实现...
};
std::vector<int, MemoryPoolAllocator> highPerformanceVec;

 8)Non-member function overloads

//1)
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 1, 2, 3 };
std::vector<int> c = { 1, 2, 3, 4 };
std::vector<int> d = { 1, 2, 4 };
std::cout << std::boolalpha;
std::cout << (a == b) << '\n';  // 输出: true(大小和元素都相同)
std::cout << (a == c) << '\n';  // 输出: false(大小不同)
std::cout << (a == d) << '\n';  // 输出: false(元素不同std::vector<int> v1 = { 1, 2, 3 };
std::vector<int> v2 = { 1, 2, 4 };
std::vector<int> v3 = { 1, 2 };
std::vector<int> v4 = { 1, 2, 3 };
std::cout << (v1 < v2) << '\n';   // 输出: true(3 < 4)
std::cout << (v1 < v3) << '\n';   // 输出: false(v3更短)
std::cout << (v1 <= v4) << '\n';  // 输出: true(v1等于v4)struct Point {int x, y;bool operator==(const Point& other) const {return x == other.x && y == other.y;}bool operator<(const Point& other) const {return (x < other.x) || (x == other.x && y < other.y);}
};
std::vector<Point> p1 = { {1, 2}, {3, 4} };
std::vector<Point> p2 = { {1, 2}, {3, 5} };
std::cout << (p1 < p2) << '\n';  // 输出: true({3,4} < {3,5})//2)
std::vector<int> a = { 1, 2, 3 };
std::vector<int> b = { 4, 5 };
// 使用非成员函数swap
swap(a, b)
//a:4,5
//b:1,2,3std::vector<int> v1 = { 1 };
std::vector<int> v2 = { 2, 3 };
// 两种方式等价
swap(v1, v2);       // 非成员函数
v1.swap(v2);        // 成员函数template<typename Container>
void exchange(Container& a, Container& b) {using std::swap;swap(a, b);  // 支持ADL,优先调用容器特化的swap
}
// 使用示例
std::vector<int> x = { 1 };
std::vector<int> y = { 2 };
exchange(x, y);  // 调用vector的swap

 9)Template specializations

std::vector<bool> bits(8, false);  // 创建8个false的位向量
bits[3] = true;  // 设置第4位为true
// 注意:不能直接获取元素地址
// bool* ptr = &bits[0];  // 错误:无法获取bit的地址
// 正确遍历方式
for (bool b : bits) {std::cout << b << ' ';  // 输出: 0 0 0 1 0 0 0 0
}
// 内存占用:通常为1字节(8位),而非8字节
std::cout << "\nSize: " << bits.size() << " elements";  // 输出: 8
std::cout << "\nCapacity: " << bits.capacity() << " elements";

 完!

http://www.lryc.cn/news/575661.html

相关文章:

  • 东芝e-STUDIO 2323AMW双面复印报计数器溢出故障
  • 【CMake基础入门教程】第七课:查找并使用第三方库(以 find_package() 为核心)
  • [论文阅读] 人工智能+ | 用大语言模型给建筑合规检查“开挂“:BIM领域的自动化革命
  • python的银行柜台管理系统
  • Python 常用正则表达式大全
  • 【51单片机5毫秒定时器】2022-6-1
  • python打卡day43
  • 常见的排序方法
  • Jenkins 部署与使用
  • 在Visual Studio使用Qt的插件机制进行开发
  • Nordic nRF54L15 SoC对包含电池监测、中断处理和电源轨控制的定制 nPM1300 示例
  • UE Universal Camera 相机插件-限制镜头在区域内移动
  • 【Docker基础】Docker容器管理:docker restart详解
  • 使用Charles中文版抓包工具进行高效的API调试与性能优化
  • 【机器学习深度学习】线性代数
  • 网络分层模型与协议体系技术研究报告
  • PDF Kit 使用示例(HarmonyOS)
  • dockers virbox 安装
  • 亚矩阵云手机多开赋能Snapchat矩阵运营:技术原理与场景化破局
  • Linux修改uboot启动延时方法详细攻略,触觉智能RK3568开发板演示
  • Go语言与云原生:Kubernetes Operator开发全流程
  • 【钓鱼预警】HW主题,无需多言
  • LLM复杂记忆存储-多会话隔离案例实战
  • swiftUI iOS16和iOS15兼容
  • 设计模式 | 原型模式
  • 专线服务器具体是指什么?
  • Nginx配置文件介绍和基本使用
  • Excel处理控件Aspose.Cells教程:如何使用 Java 将图片添加到 Excel
  • 从零构建vue3项目(二)
  • 机器学习在智能农业中的创新应用与未来趋势