C++基础知识面试必备、复习细节 (6) (容器、lambda函数)

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
    

猜你喜欢

转载自blog.csdn.net/dingdingdodo/article/details/106820689