C++ STL容器 —— vector 用法详解

C++ STL容器 —— vector 用法详解

写在前面:近期正在学习C++的STL容器,因此在这里做一下日志记录,主要介绍一些容器基本成员函数的用法, 配上实际用例,并不涉及原理。但别人的博客终究是别人的, 最好自己上手操作一下.
写的不好, 请大神手下留情.

下面说的 “运行之后” 表示: 运行上个语句之后的结果.
一行如果说的太长的话, 就得拖动下面的进度条才能看到后面的内容, 非常麻烦
因此将一段话分成了多行, 就像现在这种形式

简介

头文件:# include < vector >
动态单向数组, 只能在末端直接增删元素, 与 string 并列为最常用的容器.
点击前往: string 用法详解

构造函数

vector <int> v, v1;
//定义 int 类型的数组

vector <char> vch;
//定义 char 类型的数组

vector <string> vstr;
//定义 string 类型的数组

vector <vector<int> > vv;
//定义 int 类型的二维数组, 注意 '>' 之间的空格

vector <int> v2(10);
//定义拥有 10 个元素的数组, 每个元素默认为 0

vector <int> v3(5, 30);
//定义拥有 5 个元素的数组,并全部初始化为 30

vector <int> v4 = { 1,2,3,4 };
//定义拥有 4 个元素的数组, 初始化为{1,2,3,4}

vector <int> v5{ 1,2,3,4 };
//同上

vector <int> v6(v);
//定义新容器, 拷贝 v 所有的元素

vector <int> v7 = v;
//同上

vector <int> v8(v.begin(), v.begin() + 3);
//定义新容器, 拷贝 v 区间内所有的元素

访问 / 赋值

迭代器

包括: begin、end、rbegin、end、cbegin、cend、crbegin、crend
使用方法:

auto it=v.begin(); //相当于指针,用 *it 访问

v.begin(); 返回迭代器, 指向第一元素
v.end(); 返回迭代器, 指向最末元素的下一个位置
v.cbegin(); 返回迭代器, 指向第一元素, 类型为const
v.rbegin(); 返回反向迭代器, 指向反向迭代的第一元素
v.rend(); 返回反向迭代器, 指向反向迭代的最末元素的下一个位置
v.crbegin(); 返回反向迭代器, 指向反向迭代的第一元素, 类型为const

例: 使用正向遍历 v 数组

vector <int> v{ 1,2,3,4,5,6 };
for (auto it = v.begin(); it != v.end(); it++) {
	//注意这里是不等于end, 而不是小于end
	cout << *it <<' ';
}
输出结果为: 
1 2 3 4 5 6

例: 反向遍历 v 数组

vector <int> v{ 1,2,3,4,5,6 };
for(auto it=v.rbegin();it!=v.rend();it++){
	//注意这里还是it++, 而不是it--
	cout << *it <<' ';
}
输出结果为: 
6 5 4 3 2 1

begin和rbegin的区别
v.begin()返回迭代器,指向容器内的第一元素
v.rbegin()返回逆序迭代器,指向容器内的最后一个元素
begin和cbegin的区别
可以通过v.begin()修改容器内元素的值
不能通过v.cbegin()修改容器内元素的值

下标 / at

支持下标 [] 和 at 函数随机访问容器内元素
v[id]; 返回下标为 id 的元素, 不检查是否越界
v.at(id); 返回下标为 id 的元素, 如果越界抛出异常

assign (赋值函数)
v.assign(2, 3);
//将 2 个 3 赋值给 v
//例:v={5,6,7}
//运行之后 v={3,3}

v.assign(v1.begin(), v1.end());
//将区间内的元素赋值给 v
//例:v={5,6,7}, v1={1,2,3,4}
//运行之后 v={1,2,3,4}
swap (交换函数)
v.swap(v1);
//交换两个容器的内容
//例:v={1,2,3,4}, v1={5,6,7}
//运行之后, v={5,6,7}, v1={1,2,3,4}

常用函数

v.push_back(4);
//在末尾添加元素 4
//例:v={1,2,3}
//运行之后, v={1,2,3,4}

v.pop_back();
//删除最后一个元素
//例:v={1,2,3,4}
//运行之后, v={1,2,3}

v.front();
//返回第一元素
//例:v={1,2,3,4}
//v.front()就等于 1

v.back();
//返回最末元素
//例:v={1,2,3,4}
//v.back()就等于 4

v.clear();
//清空容器

v.empty();
//容器为空返回true, 否则返回 false

长度 / 空间 / 容量相关函数

v.size();
//返回容器内目前的元素个数
//例: v={1,2,3}
//返回 3

v.max_size();
//返回元素个数 size 的最大值
//返回一个数字, 根据编译环境的不同, 这个数字也不同, 基本没什么用.

v.resize(3);
//设置 v 的 size,影响 size 和 capacity
//设置之后 capacity >= size=3 
//例:v={1,2,3,4,5,6}
//运行之后 v={1,2,3}, 如果尺寸变小,多余的部分截掉
//例:v={1,2}
//运行之后 v={1,2,0}, 如果尺寸变大,新空间用 0 代替

v.resize(3, 2);
//设置 v 的 size,如果尺寸变大,新空间全部用 2 代替
//例: v={1,2}
//运行之后 v={1,2,2}

v.capacity();
//返回重新分配内存前 v 可以容纳的字符数,至少比size大

v.reserve(4);
//设置 v 的 capacity=4, 只影响 capacity.
//设置之后,capacity=4
//例: v={1,2,3}, 此时 v.capacity()=3
//执行之后, v.capacity()=4

添加元素

insert (插入函数)
v.insert(v.begin(), 3);
//在位置之前插入元素 3
//例: v={1,2}
//运行之后 v={3,1,2}

v.insert(v.begin(), 2, 3);
//在位置之前插入 2 个元素 3
//例: v={1,2}
//运行之后 v={3,3,1,2}

v.insert(v.begin(), v1.begin(), v1.end());
//在位置之前插入 v1 区间内所有的元素
//例: v={1,2}, v1={5,6,7},
//运行之后 v={5,6,7,1,2}
emplace系列 (插入函数)
v.emplace(v.begin(), 3);
//在位置之前插入元素 3, 相当于v.insert(v.begin(),3);
//例: v={1,2,4}
//运行之后 v={3,1,2,4}

v.emplace_back(3);
//在末端插入元素 3, 相当于v.push_back(3);
//例: v={1,2}
//运行之后 v={1,2,3}

emplace / push_back / insert的区别

  1. 原理上
    emplace是直接将在位置上构造插入的内容, 不需要生成对象
    push_back / insert是先生成具有复制内容的对象, 然后将对象的内容复制到容器里面
  2. 功能上
    emplace / push_back 只能插入一个元素
    insert 可以插入多个
  3. 性能上
    因为功能比较少, 所以 emplace 的速度要更快一点

push_back与insert的区别

  1. 功能上
    push_back只能在末端添加元素
    insert可以在任何地方添加元素
  2. 性能上
    push_back速度更快一点

注: 其实 emplace 系列还有一个函数 : emplace_front, 功能是在容器开头插入新的元素, 但是因为vector是单向数组, 因此vector里面并没有这个函数.

//补充
vector<pair<int, int>>s;
s.push_back({ 1, 2 });
s.emplace_back(1, 2);
//两者的效果是一样的,注意大小括号的区别

删除元素

erase (删除函数)
v.erase(v.begin());
//删除位置上的元素, 返回迭代器, 指向下一个元素
//例: v={1,2,3}
//运行之后 v={2,3}

v.erase(v.begin(), v.end());
//删除区间内的元素
//例: v={1,2,3}
//运行之后 v={3}
这是一个使用约瑟夫问题的解法,代码如下: ```c++ #include<bits/stdc++.h> using namespace std; #define int long long #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const int N=35005; int cnt,a[N],n,m; signed main(){ vector<int>v; IOS; while(cin>>n>>m){ v.clear(); memset(a,0,sizeof(a)); cnt=0; for(int i=1;i<=2*n;i++) v.push_back(i); while(v.size()>n){ cnt=(cnt+m-1)%v.size(); v.erase(v.begin()+cnt); } vector<int>::iterator it; for(it=v.begin();it!=v.end();it++) a[*it]=1; for(int i=1;i<=2*n;i++){ if(a[i])cout<<'G'; else cout<<'B'; if(i%50==0)cout<<endl; } cout<<endl; cout<<endl; } return 0; } ``` 接下来逐行解释代码的意思: 1. `#include<bits/stdc++.h>`:包含所有常用的头文件,方便编写程序。 2. `using namespace std;`:使用 std 命名空间。 3. `#define int long long`:将 int 定义为 long long 类型,避免整型溢出。 4. `#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)`:输入输出加速。 5. `const int N=35005;`:定义常量 N,表示人数上限。 6. `int cnt,a[N],n,m;`:定义计数器 cnt,数组 a 存放当前是否还在游戏中,n 表示人数,m 表示报数的步长。 7. `signed main(){`:程序入口。 8. `vector<int>v;`:定义一个 vector 类型的变量 v,用于存放当前仍然在游戏中的人的编号。 9. `IOS;`:加速输入输出。 10. `while(cin>>n>>m){`:循环读入 n 和 m。 11. `v.clear();`:清空存放人编号的 vector。 12. `memset(a,0,sizeof(a));`:将数组 a 的所有元素初始化为 0。 13. `cnt=0;`:计数器清零。 14. `for(int i=1;i<=2*n;i++) v.push_back(i);`:将所有人的编号存放到 vector 中。 15. `while(v.size()>n){`:当存活人数大于 n 时,继续进行游戏。 16. `cnt=(cnt+m-1)%v.size();`:计算当前被淘汰的人的编号。 17. `v.erase(v.begin()+cnt);`:将被淘汰的人从 vector 中删除。 18. `vector<int>::iterator it;`:定义一个迭代器。 19. `for(it=v.begin();it!=v.end();it++)`:遍历 vector 中剩余的人的编号。 20. `a[*it]=1;`:标记当前人仍然在游戏中。 21. `for(int i=1;i<=2*n;i++){`:遍历所有人的编号。 22. `if(a[i])cout<<'G';`:如果当前人仍然在游戏中,则输出 G。 23. `else cout<<'B';`:否则输出 B。 24. `if(i%50==0)cout<<endl;`:每输出 50 个人的编号,换行。 25. `cout<<endl;`:输出一个空白行。 26. `cout<<endl;`:输出一个空白行。 27. `}`:循环结束。 28. `return 0;`:程序结束。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值