C++—vector的介绍及使用 vector的模拟实现

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

文章目录

前言

一、vector的介绍及使用

1.1 vector的介绍

1.2 vector的使用

1.2.1 vector的定义

1.2.2 vector iterator 的使用

1.2.3 vector 空间增长问题

1.2.4 vector 增删查改

1.2.5 vector 迭代器失效问题。(重点)

1.2.6 vector 在OJ中的使用。

二、vector的模拟实现

总结



前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、vector的介绍及使用

1.1 vector的介绍

vector的文档介绍

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

1.2 vector的使用

vector学习时一定要学会查看文档:vector的文档介绍,vector在实际中非常的重要,在实际中我们熟悉常 见的接口就可以,下面列出了哪些接口是要重点掌握的。

1.2.1 vector的定义

constructor构造函数声明接口说明
vector()(重点)无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

vector构造函数的演示

1.2.2 vector iterator 的使用

iterator的使用接口说明
begin + end(重点)获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置 的iterator/const_iterator
rbegin + rend获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的 reverse_iterator

vector的迭代器使用代码的演示

1.2.3 vector 空间增长问题

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize(重点)改变vector的size
reserve(重点)改变vector的capacity
  • capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。 这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
  • reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
  • resize在开空间的同时还会进行初始化,影响size。
// 测试vector的默认扩容机制
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';}}}vs:运行结果:vs下使用的STL基本是按照1.5倍方式扩容
making foo grow:capacity changed: 1capacity changed: 2capacity changed: 3capacity changed: 4capacity changed: 6capacity changed: 9capacity changed: 13capacity changed: 19capacity changed: 28capacity changed: 42capacity changed: 63capacity changed: 94
capacity changed: 141g++运行结果:linux下使用的STL基本是按照2倍方式扩容making foo grow:capacity changed: 1capacity changed: 2capacity changed: 4capacity changed: 8capacity changed: 16capacity changed: 32capacity changed: 64capacity changed: 128
// 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
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容量接口使用代码演示

1.2.4 vector 增删查改

vector增删查改接口说明
push_back(重点)尾插
pop_back(重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[](重点)像数组一样访问

vector插入和删除代码的演示

1.2.5 vector 迭代器失效问题。(重点)

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

对于vector可能会导致其迭代器失效的操作有:

  • 1.会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、 push_back等。
#include <iostream>
using namespace std;
#include <vector>int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。*/while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
  • 2. 指定位置元素的删除操作--erase
#include <iostream>
using namespace std;
#include <vector>int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}

erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代 器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效 了。

以下代码的功能是删除vector中所有的偶数,请问那个代码是正确的,为什么?

#include <iostream>
using namespace std;
#include <vector>int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}return 0;
}int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)it = v.erase(it);else++it;}return 0;
}
  • 3. 注意:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端。
// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{vector<int> v{ 1,2,3,4,5 };for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "扩容之前,vector的容量为: " << v.capacity() << endl;// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效    v.reserve(100);cout << "扩容之后,vector的容量为: " << v.capacity() << endl;// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会// 虽然可能运行,但是输出的结果是不对的while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
//程序输出:
//1 2 3 4 5
//扩容之前,vector的容量为: 5
//扩容之后,vector的容量为 : 100
//0 2 3 4 5 409 1 2 3 4 5// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{vector<int> v{ 1,2,3,4,5 };vector<int>::iterator it = find(v.begin(), v.end(), 3);v.erase(it);cout << *it << endl;while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
//程序可以正常运行,并打印:
//4
//4 5// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{vector<int> v{ 1,2,3,4,5 };// vector<int> v{1,2,3,4,5,6};auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}for (auto e : v)cout << e << " ";cout << endl;return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
1 3 5
======================================================== =
// 使用第二组数据时,程序最终会崩溃
[sly@VM - 0 - 3 - centos 20220114]$ vim testVector.cpp
[sly@VM - 0 - 3 - centos 20220114]$ g++ testVector.cpp - std = c++11
[sly@VM - 0 - 3 - centos 20220114]$ . / a.out
Segmentation fault

从上述三个例子中可以看到:SGI STL中,迭代器失效后,代码并不一定会崩溃,但是运行结果肯定不对,如果it不在begin和end范围内,肯定会崩溃的。

  • 4. 与vector类似,string在插入+扩容操作+erase之后,迭代器也会失效
#include <string>
void TestString()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it);  ++it;}
}

迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

1.2.6 vector 在OJ中的使用。

1.只出现一次的数字i

class Solution {
public:int singleNumber(vector<int>& nums) {int value = 0;for (auto e : v){ value ^= e; }return value;}
};

2.杨辉三角

// 涉及resize / operator[]
// 核心思想:找出杨辉三角的规律,发现每一行头尾都是1,中间第[j]个数等于上一行[j-1]+[j]
class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv(numRows, vector<int>);//vv.resize(numRows, vector<int>);//vector<int>是类型T,可以忽略不写for (size_t i = 0; i < vv.size(); ++i){vv[i].resize(i + 1, 0);//开空间,并将空间都初始化为0vv.[i][0] = vv.[i][vv[i].size() - 1] = 1;}for (size_t i = 0; i < vv.size(); ++i){for (size_t j = 1; j < vv[i].size(); ++j){if (vv[i][j] == 0){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}return vv;}
};

二、vector的模拟实现

vector.h
#pragma once
#include<assert.h>
namespace bit
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){// 传值返回,生成的是返回对象的拷贝,拷贝的变量是临时变量return _start;//下标为0的位置}iterator end(){return _finish;//最后一个数据的下一个位置}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}// v2(v1)vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}// initializer_list方法的构造函数(构造+拷贝构造—>优化,直接构造)// vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };vector(initializer_list<T> il){// initializer_list的对象里面有一个size()的成员函数(两个指针相减)reserve(il.size());// initializer_list有迭代器,是原生指针for (auto& e : il){push_back(e);}}// 迭代器区间构造// 类模板的成员函数可以是函数模板:好处是:可以是其它容器的迭代器template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}// size_type 就是 size_t;value_type 就是 T// 第二个参数,不能给0,因为T不一定是int,所以要用一个T()类型的匿名对象;// 比如:string,就用string构造一个匿名对象;// 如果T是内置类型:内置类型为了兼容,有了模板之后,会进行升级(int就是0,double就是0.0,指针就是空指针)vector(size_t n, const T& val = T()){// 构造函数:n个val进行初始化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);}}void swap(vector<T>& v){// 我们期望的是调用库里面类模板的swap()函数,但是由于就近原则,它会现在局部去找,再从外部去找,// 局部找,就找到了这个函数,但是它的参数不匹配,所以要加std::std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}// v1 = v3 所有深拷贝的类都可以用现代写法 v是v3的拷贝,把V3的数据拷贝到V中vector<T>& operator=(vector<T> v){// V1想要V的数据swap(v);return *this;}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}size_t size() const{return _finish - _start;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}size_t capacity() const{return _endofstorage - _start;//空间的大小}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t old_size = size();//提前保存一下size的数据个数//memcpy(tmp, _start, size() * sizeof(T));for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];// 赋值是深拷贝}delete[] _start;_start = tmp;_finish = tmp + old_size;_endofstorage = tmp + n;}}//resize的缺省值不能是0,因为T可能是int/double/char/string/vector等类型//所以给缺省值为无参的匿名对象,T()去调用T类型的构造函数void resize(size_t n, const T& val = T()){if (n > size()){reserve(n);// 插入while (_finish < _start + n){*_finish = val;++_finish;}}else{// 删除_finish = _start + n;}}void push_back(const T& val){/*if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = val;++_finish;*/insert(end(), val);}void pop_back(){/*assert(!empty());--_finish;*/erase(--end());}bool empty(){return _start == _finish;}void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;//pos - 扩容前的_start;求pos相对于头部的相对位置reserve(capacity() == 0 ? 4 : capacity() * 2);// 如果扩容了要更新pospos = _start + len;//_start:是扩容后的下标为0的地址}iterator it = _finish - 1;while (it >= pos)//it是指针,最小的指针是空指针,指针是一个一个字节内存单元的编号{*(it + 1) = *it;--it;}*pos = val;++_finish;}iterator erase(iterator pos){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 _endofstorage = nullptr;};//template<typename T>// 函数模板template<class T>void print_vector(const vector<T>& v){for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;// typename告诉编译器 vector<T>::const_iterator是一个类型//typename vector<T>::const_iterator it = v.begin();/*auto it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;*/}void test_vector1(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);print_vector(v1);vector<double> v2;v2.push_back(1.1);v2.push_back(2.2);v2.push_back(3.1);print_vector(v2);v2.insert(v2.begin(), 11.11);print_vector(v2);v2.insert(v2.begin(), 11.11);print_vector(v2);v2.insert(v2.begin(), 11.11);print_vector(v2);v2.insert(v2.begin(), 11.11);print_vector(v2);v2.insert(v2.begin(), 11.11);print_vector(v2);v2.erase(v2.begin());print_vector(v2);v2.erase(v2.begin() + 4);print_vector(v2);/*for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;*/}void test_vector2(){//内置类型的默认构造函数,初始化:int = 0,double = 0.0,char = \0等int i = 1;int j = int();int k = int(2);vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);print_vector(v1);v1.resize(10);print_vector(v1);v1.resize(3);print_vector(v1);}void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(4);print_vector(v1);vector<int> v2(v1);print_vector(v2);vector<int> v3;v3.push_back(10);v3.push_back(20);v3.push_back(30);v1 = v3;print_vector(v1);print_vector(v3);}void test_vector4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);print_vector(v1);// 迭代器区间构造函数(用来初始化顺序表)// 这个函数的参数千万不能用++或--,因为begin()和end()返回的是值是放入临时对象中的,不能改变vector<int> v2(v1.begin() + 1, v1.end() - 1);print_vector(v2);string str("abcd");vector<int> v3(str.begin(), str.end());print_vector(v3);}void test_vector5(){vector<int> v1(10, 1);// 初始化10个1print_vector(v1);vector<int> v2(10u, 1);print_vector(v2);vector<char> v3(10, 'a');print_vector(v3);}void test_vector6(){auto x = { 1,2,3,4,5,6,7,8,9,10 };cout << typeid(x).name() << endl;cout << sizeof(x) << endl;initializer_list<int> y = { 1,2,3,4,5,6,7 };// 将{}中的数值给initializer_list<int>类型的对象y// 常量字符串为什么能初始化string?单参数的构造函数,隐式类型转换// "11111"构造一个临时对象,再将这个临时对象进行拷贝构造。string str = "11111"; // 构造 + 拷贝构造 -> 优化 直接构造// (加个&引用,就不会优化了:加&的话,只有构造,没有拷贝构造;// 但是这里编译不过去:类型转换会产生临时变量,引用的是常量字符串构造的临时对象,临时对象具有常性,所以要加const)const string& str1 = "11111"; // 构造临时对象,引用的是临时对象vector<string> v;v.push_back(str);// 有名对象v.push_back(string("22222"));// 匿名对象v.push_back("33333");// 可以不用push_back匿名对象,直接使用常量字符串// 为什么可以直接push_back常量字符串?看图int i = 1;// 不推荐 -- C++11//int j = { 1 };int k{ 1 };// 跟上面类似// 隐式类型转换+优化//vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };// C++11的用法 用initializer_list初始化vector,也是隐式类型的转换vector<int> v1{ 1,2,3,4,5,6,7,8,9,10 };//  C++11里面可以把赋值符号去掉,但是不建议这样使用for (auto e : v1){cout << e << " ";}cout << endl;// 直接构造  它和上面的隐式类型转换方法的结果都是一样的vector<int> v2({ 10,20,30,40 });for (auto e : v2){cout << e << " ";}cout << endl;}void test_vector7(){vector<string> v;v.push_back("11111");v.push_back("22222");v.push_back("33333");v.push_back("44444");v.push_back("55555");for (auto& e : v){cout << e << " ";}cout << endl;}void test_vector8(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);v1.push_back(7);v1.push_back(8);print_vector(v1);// insert以后,it就失效了,不要使用了vector<int>::iterator it = v1.begin() + 3;v1.insert(it, 40);print_vector(v1);// 如果还是想访问it的位置,那就重新更新一下it的位置it = v1.begin() + 3;cout << *it << endl;}void test_vector9(){//std::vector<int> v1;vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(4);v1.push_back(5);//v1.push_back(4);// 删除偶数 -- 迭代器失效以后,不要直接使用,如果要使用按规则重新更新后使用//std::vector<int>::iterator it = v1.begin();vector<int>::iterator it = v1.begin();//cout << typeid(it).name() << endl;while (it != v1.end()){if (*it % 2 == 0){it = v1.erase(it);// erase()函数会返回删除元素的下一个位置的迭代器,哪怕erase()函数会缩容,也会返回缩容后的空间的位置}else{++it;}}//print_vector(v1);for (auto e : v1){cout << e << " ";}cout << endl;}
}
vector.cc
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<algorithm>//算法头文件
using namespace std;#include<vector>//(int/double)顺序表void test_vector1()
{/*vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);*/vector<int> v(10, 1);//开10个空间,初始化为1//遍历:下标 + []for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;//遍历:迭代器vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;//遍历:范围forfor (auto e : v){cout << e << " ";}cout << endl;
}void test_vector2()
{size_t sz;vector<int> v;v.reserve(100);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';}}cout << v.size() << endl;cout << v.capacity() << endl;v.reserve(10);//reserve不会缩容cout << v.size() << endl;cout << v.capacity() << endl;cout << "--------------" << endl;cout << v.size() << endl;cout << v.capacity() << endl;v.resize(10);//只保留10个size,resize不会缩容cout << v.size() << endl;cout << v.capacity() << endl;v.shrink_to_fit();//缩容cout << v.size() << endl;cout << v.capacity() << endl;vector<int> a;a.resize(10, 1);//开10个空间,初始化为1for (auto e : a){cout << e << " ";}cout << endl;
}void test_vector3()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);for (auto e : v){cout << e << " ";}cout << endl;//只要是迭代区间,都是左闭右开//vector<int>::iterator pos = find(v.begin(), v.end(), 3);auto pos = find(v.begin(), v.end(), 3);if (pos != v.end())//找不到,返回的是 v.end(){v.insert(pos, 30);}// 头插v.insert(v.begin(), 0);for (auto e : v){cout << e << " ";}cout << endl;//在下标为2的位置插入0v.insert(v.begin() + 2, 0);for (auto e : v){cout << e << " ";}cout << endl;// 迭代区间不一定是自己的迭代器,vector下的iterator必须是vector的,模板的迭代器就不一定是vector的// 迭代器区间可以是属于自己的迭代器,也可以是属于其他容器的迭代器// 模拟一下不是vector下的迭代器的迭代器区间string s("abcd");v.insert(v.begin(), s.begin(), s.end());for (auto e : v){cout << e << " ";}cout << endl;
}void test_vector()
{// 对象数组,数组中的每一个对象是 stringvector<string> v;string s1("苹果");v.push_back(s1);//有名对象v.push_back(string("香蕉"));//匿名对象v.push_back("草莓");//隐式类型转换vector<vector<int>> vv;
}#include"vector.h"int main()
{//test_vector1();test_vector3();return 0;
}

对于迭代器而言:

  • vector——insert/erase都会失效;
  • list——insert不会失效,erase会失效。

总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

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

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

相关文章

JVM 八股(一)

JVM 1.类装载的执行过程 加载&#xff1a; 元空间存储构造函数&#xff0c;方法&#xff0c;字段等 验证 准备 解析 初始化 使用 2.垃圾回收 什么是垃圾回收&#xff1f;怎样找到这些垃圾&#xff1f;找到垃圾后是怎么清除的&#xff08;垃圾回收算法&#xff09;&#x…

一篇搞定AVL树+旋转【附图详解旋转思想】

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…

【C语言】贪吃蛇【附源码】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 一、游戏说明&#xff1a; 一个基于C语言链表开发的贪吃蛇游戏&#xff1a; 1. 按方向键上下左右&#xff0c;可以实现蛇移动方向的改变。 2. 短时间长按方向键上下左右其中之一&#xff0c;可实现蛇向该方向的短时间…

智能指针(C++11)

智能指针的使用 问题 我们在平时写程序的时候&#xff0c;有些情况下不可避免地会遇见内存泄露的情况。内存泄露是指因为疏忽或错误&#xff0c;造成程序未能释放已经不再使用的内存的情况。例如下面这个例子&#xff0c;内存泄漏不易被察觉。 int div() {int a, b;cin >…

【复习linux相关命令】

查看命令位置&#xff0c;查找命令 which命令 查看命令的位置 [rootVM-12-15-opencloudos ~]# which cd /usr/bin/cd [rootVM-12-15-opencloudos ~]# which java /usr/local/java/jdk1.8.0_261/bin/java [rootVM-12-15-opencloudos ~]# which pwd /usr/bin/pwdfind查找文件 …

element+Vue2,在一个页面跳转到另一个页面,并自动选中table的某一行

需求&#xff1a;点击A页面的某处&#xff0c;跳转到B页面并选中B页面表格的某一行&#xff08;点击B页面的搜索后需要清空默认选择的状态&#xff09;环境&#xff1a;vue2、element的table&#xff0c;table允许多选知识点&#xff1a;主要使用到table的这两属性&#xff1a;…

Diffusion添加噪声noise的方式有哪些?怎么向图像中添加噪声?

添加噪声的方式大致分为两种&#xff0c;一种是每张图像在任意timestep都加入一样的均匀噪声&#xff0c;另一种是按照timestep添加不同程度的噪声 一、在任意timestep都加入一样的noise batch_size 32x_start torch.rand(batch_size,3,256,256) noise torch.randn_like(x_…

亚信安全荣获2023年度5G创新应用评优活动两项大奖

近日&#xff0c;“关于2023 年度5G 创新应用评优活动评选结果”正式公布&#xff0c;亚信安全凭借在5G安全领域的深厚积累和创新实践&#xff0c;成功荣获“5G技术创新的优秀代表”和“5G应用创新的杰出实践”两项大奖。 面向异构安全能力的5G安全自动化响应系统 作为5G技术创…

【Mybatis 基础】增删改查(@Insert, @Delete, @Update, @Select)

Mybatis Insert Delete Update Select Mybatis用法基础操作 - 删除delete 传参SpringbootMybatisCrudApplicationTests 测试类删除预编译SQL 基础操作 - 插入Insert 插入SpringbootMybatisCrudApplicationTests 测试类插入对象主键返回 基础操作 - 更新UPDATE 更新SpringbootMy…

Python进阶编程 --- 1.类和对象

文章目录 第一章&#xff1a;1.初始对象1.1 使用对象组织数据1.2 类的成员方法1.2.1 类的定义和使用1.2.2 创建类对象1.2.3 成员变量和成员方法1.2.4 成员方法的定义语法1.2.5 注意事项 1.3 类和对象1.3.1 基于类创建对象 1.4 构造方法1.5 其他内置方法1.5.1 魔术方法str字符串…

(南京观海微电子)——DDIC显示触控芯片介绍

显示驱动芯片&#xff08;Display Driver Integrated Circuit&#xff0c;简称DDIC&#xff09;的主要功能是控制OLED显示面板。它需要配合OLED显示屏实现轻薄、弹性和可折叠&#xff0c;并提供广色域和高保真的显示信号。同时&#xff0c;OLED要求实现比LCD更低的功耗&#xf…

成绩管理系统|基于springboot成绩管理系统的设计与实现(附项目源码+论文)

基于springboot成绩管理系统的设计与实现 一、摘要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装毕业设计成绩管…

平衡二叉树(AVL树)

文章目录 平衡二叉树&#xff08;AVL树&#xff09;1、平衡二叉树概念2、平衡二叉树的的实现2.1、平衡二叉树的结点定义2.2、平衡二叉树的插入2.3、平衡二叉树的旋转2.3.1、右单旋&#xff08;R旋转&#xff09;2.3.2、左单旋&#xff08;L旋转&#xff09;2.3.3、先右单旋再左…

leetcode 周赛 391场

2. 换水问题 给你两个整数 numBottles 和 numExchange 。 numBottles 代表你最初拥有的满水瓶数量。在一次操作中&#xff0c;你可以执行以下操作之一&#xff1a; 喝掉任意数量的满水瓶&#xff0c;使它们变成空水瓶。用 numExchange 个空水瓶交换一个满水瓶。然后&#xf…

Django安装及第一个项目

1、安装python C:\Users\leell>py --version Python 3.10.6 可以看出我的环境python的版本3.10.6&#xff0c;比较新 2、 Python 虚拟环境创建 2.1 官网教程 目前&#xff0c;有两种常用工具可用于创建 Python 虚拟环境&#xff1a; venv 在 Python 3.3 及更高版本中默…

Vue系列——数据对象

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>el:挂载点</title> </head> <body&g…

C++11入门手册第二节,学完直接上手Qt(共两节)

C++多线程 #include <thread>:C++多线程库 #include <mutex>:C++互斥量库 #include <future>:C++异步库 多线程介绍 线程的创建 void entry_1() { }以普通函数作为线程入口函数:void entry_2(int val) { }​std::thread my_thread_1(entry_1);std::thr…

【c++】类和对象(六)深入了解隐式类型转换

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章我们来到初始化列表&#xff0c;隐式类型转换以及explicit的内容 目录 1.初始化列表1.1构造函数体赋值1.2初始化列表1.2.1隐式类型转换与复制初始化 1.3e…

C语言-写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。

0xaaaaaaaa...等是什么&#xff1f;-CSDN博客https://blog.csdn.net/Jason_from_China/article/details/137179252 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #define SWAP(num) (((num & 0xAAAAAAAA) >> 1) | ((num & 0x55555555) << …

WIFI驱动移植实验:配置 Linux 内核

一. 简介 前面文章删除了Linux内核源码&#xff08;NXP官方的kernel内核源码&#xff09;自带的 WIFI驱动。 WIFI驱动移植实验&#xff1a;删除Linux内核自带的 RTL8192CU 驱动-CSDN博客 将正点原子提供的 rtl8188EUS驱动源码添加到 kernel内核源码中。文章如下&#xff1a…