C++------vector【STL】

文章目录

  • vector的介绍及使用
    • vector的介绍
    • vector的使用
  • vector的模拟实现

vector的介绍及使用

vector的介绍

1、vector是表示可变大小数组的序列容器。
2、就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3、本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
4、vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5、因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6、与其他动态序列容器相比,vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其他不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。

vector的使用

需要重点掌握的接口

vector的构造函数

在这里插入图片描述


//    vector的构造int TestVector1()
{// constructors used in the same order as described above:vector<int> first;                                //空vector<int> second(4, 100);                       //4个100初始化vector<int> third(second.begin(), second.end());  //迭代器区间vector<int> fourth(third);                       //拷贝构造// 下面涉及迭代器初始化的部分,我们学习完迭代器再来看这部分int myints[] = { 16,2,77,29 };vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));cout << "The contents of fifth are:";for (vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)cout << ' ' << *it;cout << '\n';return 0;
}

迭代器的使用,这里是左闭右开的区间
在这里插入图片描述

在这里插入图片描述

void PrintVector(const vector<int>& v)
{// const对象使用const迭代器进行遍历打印vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;
}void TestVector2()
{// 使用push_back插入4个数据vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 使用迭代器进行遍历打印vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;// 使用迭代器进行修改it = v.begin();while (it != v.end()){*it *= 2;++it;}// 使用反向迭代器进行遍历再打印// vector<int>::reverse_iterator rit = v.rbegin();auto rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";++rit;}cout << endl;PrintVector(v);
}

vector的扩容
在这里插入图片描述

  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。
// reisze(size_t n, const T& data = T())
// 将有效元素个数设置为n个,如果时增多时,增多的元素使用data进行填充
// 注意:resize在增多元素个数时可能会扩容
void TestVector3()
{vector<int> v;// set some initial content:for (int i = 1; i < 10; i++)v.push_back(i);v.resize(5);v.resize(8, 100);v.resize(12);cout << "v contains:";for (size_t i = 0; i < v.size(); i++)cout << ' ' << v[i];cout << '\n';
}// 测试vector的默认扩容机制
// vs:按照1.5倍方式扩容
// linux:按照2倍方式扩容
void TestVectorExpand()
{size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i) {v.push_back(i);if (sz != v.capacity()) {sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}// 往vecotr中插入元素时,如果大概已经知道要存放多少个元素
// 可以通过reserve方法提前将容量设置好,避免边插入边扩容效率低
void TestVectorExpandOP()
{vector<int> v;size_t sz = v.capacity();v.reserve(100);   // 提前将容量设置好,可以避免一遍插入一遍扩容cout << "making bar grow:\n";for (int i = 0; i < 100; ++i) {v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

vector的增删查改
在这里插入图片描述
在这里插入图片描述

// 尾插和尾删:push_back/pop_back
void TestVector4()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);auto it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;v.pop_back();v.pop_back();it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;
}// 任意位置插入:insert和erase,以及查找find
// 注意find不是vector自身提供的方法,是STL提供的算法
void TestVector5()
{// 使用列表方式初始化,C++11新语法vector<int> v{ 1, 2, 3, 4 };// 在指定位置前插入值为val的元素,比如:3之前插入30,如果没有则不插入// 1. 先使用find查找3所在位置// 注意:vector没有提供find方法,如果要查找只能使用STL提供的全局findauto pos = find(v.begin(), v.end(), 3);if (pos != v.end()){// 2. 在pos位置之前插入30v.insert(pos, 30);}vector<int>::iterator it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据v.erase(pos);it = v.begin();while (it != v.end()) {cout << *it << " ";++it;}cout << endl;
}// operator[]+index 和 C++11中vector的新式for+auto的遍历
// vector使用这两种遍历方式是比较便捷的。
void TestVector6()
{vector<int> v{ 1, 2, 3, 4 };// 通过[]读写第0个位置。v[0] = 10;cout << v[0] << endl;// 1. 使用for+[]小标方式遍历for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;vector<int> swapv;swapv.swap(v);cout << "v data:";for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;// 2. 使用迭代器遍历cout << "swapv data:";auto it = swapv.begin();while (it != swapv.end()){cout << *it << " ";++it;}// 3. 使用范围for遍历for (auto x : v)cout << x << " ";cout << endl;
}

vector迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
迭代器失效的情况:扩容后迭代器失效,删除时迭代器失效。
解决方法:
迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

vector的模拟实现

#pragma once
#include <iostream>
#include <assert.h>
namespace vec
{template<class T>class vector{typedef T* iterator;typedef const T* const_iterator;public:vector(){}//内置类型也可以有构造函数,我们下一次再说vector(size_t n, const T& it = T()){resize(n, it);}vector(int n, const T& val = T()){resize(n, val);}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];//拷贝原有的数据if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}void push_back(const T& x){//考虑增容的情况if (_finish == _endofstorage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}//*_finish = x;//_finish++;insert(end(), x);}iterator erase(iterator pos){//考虑pos位置的合法性assert(pos >= _start && pos < _finish);//移动数据iterator p = pos + 1;while (p != _finish){*(p - 1) = *p;p++;}_finish--;return pos;}void resize(size_t n, const T& x = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*_finish = x;_finish++;}}}iterator insert(iterator pos, const T& x){//判断pos位置的合法性assert(pos >= _start && pos <= _finish);//考虑扩容if (_finish == _endofstorage){//解决迭代器失效问题size_t len = _finish - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);pos = _start + len;}//开始插入数据//移动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}//插入数据*pos = x;_finish++;return pos;}void pop_back(){erase(--end());}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}//拷贝构造vector(const vector<T>& v){//深度拷贝_start = new T[v.capacity()];for (size_t i = 0; i <v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_endofstorage = _start + v.capacity();}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}//赋值运算符重载vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _endofstorage = nullptr;}}void print(const vector<T>& v){for (auto e : v){std::cout << e << " ";}std::cout << std::endl;}private:iterator _start;iterator _finish;iterator _endofstorage;};
}

好的,我们下一篇再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/96054.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尚硅谷SpringMVC (5-8)

五、域对象共享数据 1、使用ServletAPI向request域对象共享数据 首页&#xff1a; Controller public class TestController {RequestMapping("/")public String index(){return "index";} } <!DOCTYPE html> <html lang"en" xmln…

pdf转换成图片转换器在线怎么转?pdf转换成图片具体方法介绍

很多用户们都是比较喜欢使用pdf文档的&#xff0c;由于这种文件格式的便携性非常高&#xff0c;所以广泛的应用于工作和学习领域&#xff0c;再加上pdf文档可以随意转换成为其他的文件格式&#xff0c;更是让pdf文档受到了更多用户们的欢迎&#xff0c;那么pdf转换成图片转换器…

【Kubernetes理论篇】2023年最新CKA考题+解析

文章目录 第一题&#xff1a;RBAC授权访问控制第二题&#xff1a;Node节点维护第三题&#xff1a;K8S集群版本升级第四题&#xff1a;ETCD数据库备份恢复第五题&#xff1a;NetworkPolicy网络策略第六题&#xff1a;Service四层负载第七题&#xff1a;Ingress七层负载第八题&am…

jupyter常用的方法以及快捷键

选中状态 蓝色 按enter 进入编辑状态 编辑状态 绿色 按Esc 进入选中状态 Code模式运行是运行代码 Markdown模式运行是进入预览状态 - - - 是文本格式的一种精简的语法形式 Raw NBConvert 是默认文本状态 - - - 输入什么样 展示什么样 Y - - - 切换code模式 M - - - 切换Markdo…

WideDeep模型介绍

文章目录 1. Wide&Deep模型的记忆能力和泛化能力2. Wide&Deep模型的结构3. Wide&Deep模型的进化——Deep&Cross模型4. Wide&Deep模型的影响力 Wide&Deep模型是 记忆能力和 泛化能力的综合&#xff0c;是谷歌在2016年提出的。正如其名&#xff0c;Wid…

vscode 对模型train、detect脚本进行Debug时配置参数

我们训练yolov5代码时&#xff0c;一般会配置一些参数&#xff0c;比如模型权重文件--weights, 模型的配置文件--cfg, 以及训练的数据--data, 对应的训练脚本为: 训练train python train.py -- weights ./yolov5s.pt --cfg models\yolov5s.yaml --data ./data/coco128.yaml…

乐理-笔记

乐理笔记整理 1、前言2、认识钢琴键盘及音名3、升降号、还原号4、如何区分同一音名的不同键&#xff1f;5、各类音符时值的关系6、歌曲拍号7、拍号的强弱规律8、歌曲速度&#xff08;BPM&#xff09;9、附点音符10、三连音12、唱名与简谱数字13、自然大调&#xff08;白键&…

C#关于WebService中File.Exists()处理远程路径的异常记录

目录 前言方案一打开网站对应的程序池的高级设置按下图步骤设置凭据重启网站若方案一未能解决&#xff0c;请继续尝试方案二&#x1f447; 方案二从控制面板进入到 凭据管理器为windows凭据添加凭据点击**Windows凭据**&#xff0c;并点击**添加Windows凭据**键入远程路径的地址…

人工智能轨道交通行业周刊-第58期(2023.8.28-9.3)

本期关键词&#xff1a;成都智慧工厂、机务段、站台地标、备案大模型、AIGC报告 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界铁路…

elasticsearch8.9.1集群搭建

目录 1.官网文档 2.安装步骤 2.1 环境准备 2.2 添加用户 2.3 修改文件profile文件 2.4 修改elasticsearch.yml 2.5 修改 sysctl.conf 3.启动 3.1 切换到kibana 3.2 启动elasticsearch 3.3 启动kibana 3.4 验证节点情况 1.官网文档 elasticsearch文档&#xff1a;ht…

怎样来实现流量削峰方案

削峰从本质上来说就是更多地延缓用户请求&#xff0c;以及层层过滤用户的访问需求&#xff0c;遵从“最后落地到数据库的请求数要尽量少”的原则。 1.消息队列解决削峰 要对流量进行削峰&#xff0c;最容易想到的解决方案就是用消息队列来缓冲瞬时流量&#xff0c;把同步的直…

TDesign表单rules通过函数 实现复杂逻辑验证输入内容

Element ui 中 我们可以通过validator 绑定函数来验证一些不在表单model中的值 又或者处理一下比较复杂的判断逻辑 TDesign也有validator 但比较直观的说 没有Element那么好用 这里 我们给validator绑定了我们自己的checkAge函数 这个函数中 只有一个参数 value 而且 如果你的…