一. vector 容器

vector 容器是标准库中的一种顺序容器,它是可变大小数组,支持快速随机访问。在尾部之外的位置插入或删除元素可能会很慢

创建 vector 容器

std::vector<int> vec_1 = {1, 2, 3, 4};
std::vector<int> vec_1 = {1, 2, 3, 4};
std::vector<int> vec_2(vec_1);
std::vector<int> vec_1(5, 1);

访问 vector 容器

for(const auto &elem : vec_1)                                                                                                                       
    printf("%d ", elem);                                                                                                                            
printf("\n");
for(int i = 0; i < vec_1.size(); ++i)
    printf("%d ", vec_1[i]);
printf("\n");
for(auto iter = vec_1.begin(); iter != vec_1.end(); ++iter)
    printf("%d ", *iter);
printf("\n");

尾部插入元素

std::vector<int> vec_1;
vec_1.emplace_back(1);
vec_1.emplace_back(2);
vec_1.emplace_back(3);

尾部删除元素

vec_1.pop_back();
vec_1.pop_back();
vec_1.pop_back();

删除迭代器指定范围的元素

std::vector<int> vec_1 = {1, 2, 2, 4, 5};
vec_1.erase(vec_1.begin()+1, vec_1.end()-2);

如何删除 vector 容器中满足一定条件的元素?

二. lambda 表达式

2.1 简介

lambda 表达式表示一个可调用的代码单元,可以将其理解为匿名函数,和函数不同的是,lambda 可能定义在函数内部。

[capture list](parameter list) -> return type {function body} 

形参列表与返回类型可以省略,但是必须永远包含捕获列表与函数

捕获列表用来捕获当前函数作用域的 0 个或多个变量,变量之间用逗号隔开。有两种捕获方式:按值捕获和按引用捕获

2.2 练习

比大小

#include <cstdio>

int main(void){
    auto lambda_1 = [](int num_1, int num_2){ return num_1 >= num_2? num_1 : num_2; };
    printf("Max: %d\n", lambda_1(4, 5));
    return 0;
}

求绝对值

#include <cstdio>

int main(void){                                                                                                                                         
    auto lambda_1 = [](int num_1){ return num_1 >= 0? num_1 : -num_1; };                                                                                
    printf("Abs: %d\n", lambda_1(-7));
    return 0;
}

求平方

#include <cstdio>

int main(void){                                                                                                                                         
    auto lambda_1 = [](int num_1){ return num_1 * num_1; };                                                                                             
    printf("Sqrt: %d\n", lambda_1(-7));                                                                                                                  
    return 0;                                                                                                                                           
}

2.3 按值捕获

捕获列表只能捕获非静态的局部变量,对于静态局部变量和全局变量,直接拿来使用就可以了

值捕获是将捕获变量拷贝到 lambda 表达式内,因此要求捕获变量可以拷贝;并且默认无法改变捕获变量的值;但可通过 mutable 说明符移除 lambda 表达式的常量性,此时 parameter list 不可省略;

#include <cstdio>                                                                                                                                     

int num_1 = 999;

int main(void){
    // 报错!!!,无法捕获全局变量
    auto lambda_1 = [num_1]{ return num_1 * num_1; };
    printf("Test: %d\n", lambda_1());
    return 0;
}
 #include <cstdio>                                                                                                                                     

int main(void){                                                                                                                                       
    int num_1 = 999;
    auto lambda_1 = [num_1]{ 
        // 报错!!!,值捕获的变量默认为常量
        ++num_1; 
        printf("Test: %d\n", num_1);
        return;
    };
    lambda_1();
    return 0;
}
#include <cstdio>
 
int main(void){                                                                                                                                         
    int num_1 = 999;                                                                                                                                    
    auto lambda_1 = [num_1]() mutable { 
        ++num_1; 
        printf("num_1: %d\n", num_1);
        return;
    };
    lambda_1();
    lambda_1();
    lambda_1();
    printf("num_1: %d\n", num_1);
    return 0;
}

可以发现

  1. 按值捕获,无论在 lambda 表达式内如何改变捕获变量的值,不会影响外部作用域
  2. 但是,它却能影响下次调用 lambda 表达式时捕获变量的值
  3. 按值捕获,捕获变量的值在 lambda 表达式定义的时候就固定下来了,之后无论如何修改外部作用域的值,lambda 捕获的值都不会变化

2.4 按引用捕获

按引用捕获只需在捕获变量前加 &

#include <cstdio>

int main(void){                                                                                                                                         
    int num_1 = 999;                                                                                                                                    
    int num_2 = 666;                                                                                                                                    
    auto lambda_1 = [&num_1, &num_2](){                                                                                                                 
        ++num_1;                                                                                                                                        
        ++num_2;
        return;
    };
    
    printf("num_1: %d, num_2: %d\n", num_1, num_2);
    lambda_1();
    printf("num_1: %d, num_2: %d\n", num_1, num_2);
    return 0;
}

按引用捕获,可以改变捕获变量的值,并且会影响外部作用域

使用 lambda 表达式时,优先使用按值捕获,必要时使用按引用捕获

三. STL 常用算法

3.1 映射

transform(begin, end, result, op);

1. begin:容器的开始迭代器
2. end:容器的结束迭代器
3. result:存放结果的开始迭代器
4. op: 可调用对象
#include <cstdio>                                                                                                                                       
#include <vector>
#include <algorithm>

int main(void){
    std::vector<int> vec_1 = {1, 2, 3, 4};
    show(vec_1);
    
    // 平方 
    std::transform(vec_1.begin(), vec_1.end(), vec_1.begin(), [](int elem){ return elem * elem; });
    show(vec_1);
    return 0;
}
int main(void){
    std::vector<int> vec_1 = {1, 2, 3, 4};
    show(vec_1);

    // 取反 
    std::transform(vec_1.begin(), vec_1.end(), vec_1.begin(), [](int elem){ return -elem; });
    show(vec_1);
    return 0;
}

3.2 过滤

remove_if(begin, end, op)

1. begin:容器的开始迭代器
2. end:容器的结束迭代器
3. op: 谓词

remove_if 并不会实际移除容器中的元素,只是将应该移除的元素都移动到了容器尾部,并返回一个分界的迭代器
int main(void){
    std::vector<int> vec_1 = {1, 2, 3, 4};
    show(vec_1);

    // 过滤偶数
    vec_1.erase(std::remove_if(vec_1.begin(), vec_1.end(), [](int elem){ return elem % 2 == 0; }), vec_1.end());
    show(vec_1);
    return 0;
}
int main(void){
    std::vector<int> vec_1 = {-1, 2, -3, 4};
    show(vec_1);

    // 过滤负数
    vec_1.erase(std::remove_if(vec_1.begin(), vec_1.end(), [](int elem){ return elem < 0; }), vec_1.end());
    show(vec_1);
    return 0;
}

3.3 折叠

accumulate(begin, end, init, op)

1. begin:容器的开始迭代器
2. end:容器的结束迭代器
3. init:初始值
4. op: 可调用对象
int main(void){
    std::vector<int> vec_1 = {1, 2, 3, 4};
    show(vec_1);

    // 累加
    int res = std::accumulate(vec_1.begin(), vec_1.end(), 0, [](int elem_1, int elem_2){ return elem_1 + elem_2; });    
    printf("Res: %d\n", res);
    return 0;
}
int main(void){
    std::vector<int> vec_1 = {1, 2, 3, 4};
    show(vec_1);

    // 累乘
    int res = std::accumulate(vec_1.begin(), vec_1.end(), 1, [](int elem_1, int elem_2){ return elem_1 * elem_2; });    
    printf("Res: %d\n", res);
    return 0;
}

标准库中,还有一些顺序容器,如 deque 双端队列、list 双向链表、forward_list 单向链表和 array 固定大小数组。

作业

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。

根据维基百科上 h 指数的定义:h 代表“高引用次数”,一名科研人员的 h指数是指他(她)的 (n 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。且其余的 n - h 篇论文每篇被引用次数 不超过 h 次。

如果 h 有多种可能的值,h 指数 是其中最大的那个。

示例 1:输入:citations = [3,0,6,1,5]

输出:3

解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。

示例 2:输入:citations = [1,3,1]

输出:1