C/C++你必须了解的小知识(38)

238 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第7天,点击查看活动详情

===

  1. 无序容器(哈希表)

    用法和功能同map一模一样,区别在于哈希表的效率更高。

    (1) 无序容器具有以下 2 个特点:

    ​ a. 无序容器内部存储的键值对是无序的,各键值对的存储位置取决于该键值对中的键,

    ​ b. 和关联式容器相比,无序容器擅长通过指定键查找对应的值(平均时间复杂度为 O(1));但对于使用迭代器遍历容器中存储的元素,无序容器的执行效率则不如关联式容器。

    (2) 和关联式容器一样,无序容器只是一类容器的统称,其包含有 4 个具体容器,分别为 unordered_map、unordered_multimap、unordered_set 以及 unordered_multiset。功能如下表:

    无序容器功能
    unordered_map存储键值对 <key, value> 类型的元素,其中各个键值对键的值不允许重复,且该容器中存储的键值对是无序的。
    unordered_multimap和 unordered_map 唯一的区别在于,该容器允许存储多个键相同的键值对。
    unordered_set不再以键值对的形式存储数据,而是直接存储数据元素本身(当然也可以理解为,该容器存储的全部都是键 key 和值 value 相等的键值对,正因为它们相等,因此只存储 value 即可)。另外,该容器存储的元素不能重复,且容器内部存储的元素也是无序的。
    unordered_multiset和 unordered_set 唯一的区别在于,该容器允许存储值相同的元素。

    (3) 程序实例(以 unordered_map 容器为例)

    #include <iostream>
    #include <string>
    #include <unordered_map>
    using namespace std;
    int main()
    {
        //创建并初始化一个 unordered_map 容器,其存储的 <string,string> 类型的键值对
        std::unordered_map<std::string, std::string> my_uMap{
            {"教程1","www.123.com"},
            {"教程2","www.234.com"},
            {"教程3","www.345.com"} };
        //查找指定键对应的值,效率比关联式容器高
        string str = my_uMap.at("C语言教程");
        cout << "str = " << str << endl;
        //使用迭代器遍历哈希容器,效率不如关联式容器
        for (auto iter = my_uMap.begin(); iter != my_uMap.end(); ++iter)
        {
            //pair 类型键值对分为 2 部分
            cout << iter->first << " " << iter->second << endl;
        }
        return 0;
    }
    
    /*    程序运行结果:
              教程1 www.123.com
              教程2 www.234.com
              教程3 www.345.com
    */            
    
  2. 正则表达式

    可以认为正则表达式实质上是一个字符串,该字符串描述了一种特定模式的字符串。常用符号的意义如下:

    符号意义
    ^匹配行的开头
    $匹配行的结尾
    .匹配任意单个字符
    […]匹配[]中的任意一个字符
    (…)设定分组
    \转义字符
    \d匹配数字[0-9]
    \D\d 取反
    \w匹配字母[a-z],数字,下划线
    \W\w 取反
    \s匹配空格
    \S\s 取反
    +前面的元素重复1次或多次
    *前面的元素重复任意次
    ?前面的元素重复0次或1次
    {n}前面的元素重复n次
    {n,}前面的元素重复至少n次
    {n,m}前面的元素重复至少n次,至多m次
    逻辑或
  3. Lambda匿名函数

    所谓匿名函数,简单地理解就是没有名称的函数,又常被称为 lambda 函数或者 lambda 表达式。

    (1)定义

    ​ lambda 匿名函数很简单,可以套用如下的语法格式:

    ​ [外部变量访问方式说明符] (参数) mutable noexcept/throw() -> 返回值类型
    ​ {
    ​ 函数体;
    ​ };

    其中各部分的含义分别为:

    a. [外部变量方位方式说明符]

    [ ] 方括号用于向编译器表明当前是一个 lambda 表达式,其不能被省略。在方括号内部,可以注明当前 lambda 函数的函数体中可以使用哪些“外部变量”。
    

    ​ 所谓外部变量,指的是和当前 lambda 表达式位于同一作用域内的所有局部变量。

    b. (参数)

    和普通函数的定义一样,lambda 匿名函数也可以接收外部传递的多个参数。和普通函数不同的是,如果不需要传递参数,可以连同 () 小括号一起省略;
    

    c. mutable

    此关键字可以省略,如果使用则之前的 () 小括号将不能省略(参数个数可以为 0)。默认情况下,对于以值传递方式引入的外部变量,不允许在 lambda 表达式内部修改它们的值(可以理解为这部分变量都是 const 常量)。而如果想修改它们,就必须使用 mutable 关键字。
    

    ​ 注意: 对于以值传递方式引入的外部变量,lambda 表达式修改的是拷贝的那一份,并不会修改真正的外部变量;

    d. noexcept/throw()

    可以省略,如果使用,在之前的 () 小括号将不能省略(参数个数可以为 0)。默认情况下,lambda 函数的函数体中可以抛出任何类型的异常。而标注 noexcept 关键字,则表示函数体内不会抛出任何异常;使用 throw() 可以指定 lambda 函数内部可以抛出的异常类型。
    

    e. -> 返回值类型

    指明 lambda 匿名函数的返回值类型。值得一提的是,如果 lambda 函数体内只有一个 return 语句,或者该函数返回 void,则编译器可以自行推断出返回值类型,此情况下可以直接省略"-> 返回值类型"

    f. 函数体

    和普通函数一样,lambda 匿名函数包含的内部代码都放置在函数体中。该函数体内除了可以使用指定传递进来的参数之外,还可以使用指定的外部变量以及全局范围内的所有全局变量。
    

    (2)程序实例

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int num[4] = {4, 2, 3, 1};
    //对 a 数组中的元素进行排序
    sort(num, num+4, [=](int x, int y) -> bool{ return x < y; } );
    for(int n : num){
        cout << n << " ";
    }
    return 0;
}

/*    程序运行结果:
          1 2 3 4
*/