C++基础知识面试必备、复习细节 (6)
常见的顺序容器
顺序容器类型 | 特点 |
---|---|
vector | 可变大小的数组。支持快速随机访问。在尾部之外的位置插入或删除元素代价较高 |
list | 双向链表。支持双向顺序访问。任意位置的插入删除都效率较高,不支持快速访问 |
forward_list | 单向链表。支持单向顺序访问,任意位置插入删除效率较高。 |
string | 可变大小的保存字符的容器。支持快速随机访问。尾部插入删除速度快 |
array | 固定大小数组。支持快速随机访问。不能添加或删除元素 |
deque | 双端队列。支持快速随机访问,头尾插入较快。 |
-
通常使用vector,除非有更好的理由选择其他容器
-
如果程序需要在容器中间插入删除,使用list或forward_list效率较高
-
如果程序需要随机访问元素,则使用vector或deque较好
-
迭代器的范围: [begin,end),即begin代表第一个元素,而end是最后一个元素之后的一个元素
-
vector的初始化:vector<int>为例
vector<int> a; //默认构造函数 vector<int> a(10); //初始化size为10的vector vector<int> a(10,1); //10个元素,初始值均为1 vector<int> a{1,2,3,4,5}; //初始化列表拷贝
-
array的初始化
array<int,40> a; //大小为40的int数组 array<int,10> b={1}; //第一个元素为1,其余为0 //内置数组不支持拷贝或赋值,但是array支持,只需要操作合法即可 array<int,10> c={0,1,2,3,4,5,6,7,8,9}; array<int,10> d=c;
vector对象是如何增长的
-
vector支持快速随机访问元素,因此必须将元素连续存储,又支持容量动态改变
-
vector实现时记录有两个大小:size 和 capacity
size是已经保存的元素的数目,capacity是在不分配新的内存空间的前提下最多能容纳的元素数量
vector<int> f(5,1); cout << f.size()<<' '<<f.capacity()<<' '; // 5,5 f.push_back(1); cout << f.size() << ' ' << f.capacity() << ' '; //6 10
-
Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素
-
不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容。
-
扩容倍数实际上是时间和空间的一种权衡,当倍数大时对空间浪费严重,倍数小时可能导致频繁的扩容。
string的一些方法
- s.substr(pos,n) 返回一个字符串,返回s中从pos开始的n个字符串的拷贝
- s.insert(pos,args) 在pos之前插入args制定的字符,pos为下标或迭代器
- s.find(s1) 在s中查找s1,如果有返回第一个匹配位置的下标,否则返回 npos
- s.compare(s1) 比较两个字符串,判断s是否等于、大于或小于s1,返回0、正数或负数
- to_string(T a) 将a转换为string类型返回,通常转换的是数值类型
容器适配器
容器适配器名称 | 特点 |
---|---|
stack | 先入后出。头文件 <stack> top()返回栈顶部元素 push()加入元素 pop()删除元素 |
queue | 先入先出。头文件<queue> front()返回队列首元素 back()返回队列尾元素 push()加入元素 pop()删除元素 |
priority_queue | 带优先级的队列。根据设立的优先级规则进行队列的排序。 头文件<queue> 默认是最大堆 push()加入元素 pop()删除元素 |
priority_queue<Type, Container, Functional>
//
priority_queue <int,vector<int>,greater<int> > q; //最小堆
priority_queue <int,vector<int>,less<int> > q; //最大堆
常用的泛型算法
- find(vec.cbegin(),vec.cend(),val) 如果val出现在vec中,则返回第一次出现的位置,否则返回vec.end()
- accumulate(vec.cbegin(),vec.cend(),val) 返回vec中元素的和,val为sum的初值
- fill(vec.begin(),vec.end(),val) 将每个元素都填为val
- sort(vec.begin(),vec.end(),cmp) 排序vec ,可以重写cmp
lambda表达式
-
C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,简化编程工作
-
lambda表达式常用于algorithm库中的一些泛型函数的参数
-
lambda的语法:
[capture list] (parameter list)-> return type{function body} //capture list:捕获列表 lambda所在函数中定义的局部变量列表 //paremeter list:形参列表 //return type:返回类型 //function body:函数体
-
可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
-
写一个lambda函数来调用sort从大到小排序
vector<int> nums{1,3,2,5,4}; sort(nums.begin(), nums.end(), [](int a1,int a2) { return a1 > a2; }); for(auto &i:nums) cout << i << ' '; //5,4,3,2,1
-
用lambda函数作为for_each的参数执行操作
vector<int> nums{1,3,2,5,4}; sort(nums.begin(), nums.end(), [](int &a1,int &a2) { return a1 > a2; }); for_each(nums.begin(), nums.end(), [](int &a) { cout << a << ' '; });
-
注意lambda函数的值捕获与引用捕获
//---------------引用捕获----------- int a = 1; auto f2 = [&a] { return a; }; a = 0; auto j = f2(); cout << j << endl; //输出为0,因为捕获的a发生了变化将随之变化 //----------------值捕获------------- int a = 1; auto f2 = [a] { return a; }; a = 0; auto j = f2(); cout << j << endl; //输出为1,在a改为0之前其值已经被拷贝并捕获,a发生变化不影响
因此如果希望在lambda函数中修改局部变量的值,则使用引用捕获
-
可以通过将捕获列表的值设为 = , 则将值捕获所有的该函数可见的局部变量;
将捕获类别的值设为 &,则将引用捕获所有的函数可见的局部变量
-
默认情况下,如果一个lambda体包含return之外的任何语句,则编译器认为该lambda返回为空
//两个函数等价 [](int i){return i<0?-i:i;}; [](int i)->int{if(i<0) return -i;else return i;}; //必须声明返回->int