Skip to content

📒 ​C ++ 语法笔记


一、C --> C++


1.1 命名空间


  • 命名空间( Namespace ):

    • 命名空间是 C++ 中用来组织代码的一种机制,它可以将标识符

      (如变量名、函数名、类名等)分组,避免命名冲突。

    • C++ 标准库中的所有标识符都定义在 std 命名空间中。

      例如,std::coutstd::cinstd::vector 等。


  • using namespace std; 的作用:

    • 这句代码的作用是将 std 命名空间中的所有标识符引入到当前作用域中,

      这样就可以直接使用 std 命名空间中的标识符,而不需要在每个标识符前面加上 std:: 前缀。

    • 例如,使用 using namespace std; 后,可以直接写 coutcin

      而不需要写 std::coutstd::cin


  • 示例代码:
c++
#include <iostream>

using namespace std;

int main()
{
    cout << "Hello, World!" << endl; //endl 是换行
    return 0;
}

1.2 输入输出


  • C:主要使用 printfscanf 函数进行输入输出。例如:
c
#include <stdio.h>
int main()
{
    int num;
    printf("请输入一个数字:");
    scanf("%d", &num);
    printf("你输入的数字是:%d\n", num);
    return 0;
}
  • C++ : 使用输入输出流 cincout ,更加灵活和方便。例如:
c++
#include <iostream>

using namespace std;

int main()
{
    int num;
    cout << "请输入一个数字:";
    cin >> num;
    cout << "你输入的数字是:" << num << endl;  // endl 是换行
    return 0;
}

1.3 内存管理


  • C :主要使用 mallocfree 等函数进行动态内存分配和释放。例如:
c
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int* ptr = (int*)malloc(sizeof(int));
    if (ptr != NULL)
    {
        *ptr = 10;
        printf("分配的内存中的值:%d\n", *ptr);
        free(ptr);
    }
    return 0;
}
  • C++:使用 newdelete 操作符进行动态内存分配和释放。例如:
c++
#include <iostream>

using namespace std;

int main()
{
    int* ptr = new int;
    *ptr = 10;
    cout << "分配的内存中的值:" << *ptr << endl;
    delete ptr;
    return 0;
}

1.4 函数重载


  • C : 函数名必须唯一,不能有重载的概念。

  • C++ : 支持函数重载,即可以有多个同名函数,只要它们的参数类型或参数个数不同即可。例如:

c++
#include <iostream>

using namespace std;

void print(int num)
{
    cout << "打印的数字是:" << num << endl;
}
void print(double num)
{
    cout << "打印的浮点数是:" << num << endl;
}
int main()
{
    print(10);
    print(3.14);
    return 0;
}

1.5 引用


  • C : 没有引用的概念,只有指针。

  • C++ : 引入了引用的概念,引用是一个变量的别名。例如:

    • 优点:引用可以避免指针的复杂操作,并且可以提高代码的可读性。

      在函数参数传递中,引用可以避免拷贝,提高效率。

c++
#include <iostream>

using namespace std;

void swap(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}
int main()
{
    int x = 10, y = 20;
    swap(x, y);
    cout << "x = " << x << ", y = " << y << endl;
    return 0;
}

二、C++ の STL


2.1 概述


  • 🔍 什么是 STL

  • STLC++ 标准库的一部分,提供了一套通用的、模板化的数据结构和算法。

    它让你可以高效地处理数据,而不用自己写底层逻辑。


  • 📦 简述 STL 的三大核心组件
组件作用示例
容器存储数据vector<int>map<string,int>
算法操作数据(排序、查找等)sort() , find()
迭代器连接容器和算法的 "桥梁"vector<int>::iterator

2.2 快速上手


  • 第一个 STL 程序:用 vector 存数据并排序
c++
// 用 vector 存数据并排序
#include <iostream>
#include <vector>       // 使用 stl 的 vector 来存储
#include <algorithm>  // 用于 sort

using namespace std;

int main()
{
    // 定义并初始化一个vector
    vector<int> nums = {5, 2, 8, 1, 3};
    
    // 使用 sort 进行排序
    // 补充:begin() 指向第一个位置; end() 指向最后一个元素的下一个位置
    sort(nums.begin(),nums.end());
    
    // 使用 for 的范围遍历进行输出
    for(int n: nums){
        cout << n << endl;
    }
    
    return 0;
}

📌 练习:

  • 创建一个 vector,存入 {3.1, 1.4, 2.5, 4.7} ,排序后输出。
  • 尝试用 std::reverse(nums.begin(), nums.end()) 反转顺序, 然后逆序输出。
🏷️示例代码:
c++
#include <iostream>
#include <vector>
#include <algorithm>    // 使用 sort 和 reverse

using namespace std;

int main()
{
    // 创建一个存储浮点数的 vector 并初始化
    vector<double> nums = {3.1, 1.4, 2.5, 4.7};
    
    // 排序
    sort(nums.begin(),nums.end());
    
    // 升序输出
    for(double n: nums){
        cout << n << ' ';
    }
    
    cout << endl << "---------" << endl;
    
    // 反转
    reverse(nums.begin(), nums.end());
    
    // 降序输出
    for(double n : nums){
        cout << n << ' ';
    }
    
    return 0;
}

2.3 深入理解 vector


2.3.1 概述


  • 在前面的 快速上手 里已经使用过 vector 了,

    它也是 是 C++ 里最常用的序列容器, 所以我们可以先从它下手,深入了解一下

  • vector : 动态数组, “变长数组” ,“倍增的思想” ,内存连续,支持随机访问,尾部插入快


  • 常用 10 条 命令:
目的代码示例复杂度
① 创建vector<int> vO(1)
② 尾增v.push_back(7);均摊 O(1)
③ 尾删v.pop_back();O(1)
④ 长度v.size();O(1)
⑤ 判空v.empty();O(1)
⑥ 下标访问v[i] or v.at(i)O(1)
⑦ 遍历1. 范围遍历: for(int x : v)
2. 遍历下标访问: for(int i; i < v.size(); i++)
3. 迭代器遍历: for(vector<int>::iterator i = v.begin(); i!=v.end(); i++)
O(n)
⑧ 清空v.clear();O(n)
⑨ 前后元素v.front()v.back()O(1)
⑩ 前后指针v.begin()v.end()O(n)

2.3.2 构造 & 初始化


c++
vector<int> a;				// 创建一个空 vector
vector<int> a(10);          // 10 个 0
vector<int> b(10, 3);       // 10 个 3
vector<int> c{1,2,3,4};     // 列表初始化 C++11
vector<string> d = {"abc", "def"}; // 存储字符串的 vector

int arr[] = {9,8,7};
vector<int> e(arr, arr+3);  // 从 C 数组拷贝
vector<int> f(e.begin(), e.end()); // 从另一容器拷贝

2.3.3 基本操作


c++
#include <iostream>
#include <vector>

using namespace std;

// 自定义一个打印 vector 的函数
void print(vector<int> a){
    for(int x : a){
        cout << x << ' ';
    }
    cout << endl;
}

int main()
{
    vector<int> nums; 	// 创建一个空 vector
    
    nums.push_back(2);  // 尾部新增元素
    nums.push_back(3);
    nums.push_back(1);
    nums.push_back(4);
    print(nums);        // 2 3 1 4 
    nums.pop_back();    // 尾部删除元素
    print(nums);        // 2 3 1
    
    // 第一个元素
    cout << nums.front() << endl; // 2
    // 最后一个元素
    cout << nums.back() << endl;  // 1
    
    // vector 大小
    cout << nums.size() << endl; // 3
    
    // 清空
    nums.clear();
    cout << nums.size() << endl; // 0

    return 0;
}

2.3.4 插入 & 删除


  • insert / erase : “ 动中间 ” 的接口
  • insert :
    • 返回指向插入元素的迭代器
    • 所有后面的元素整体后移一位 O(n)
    • 如果 size()==capacity() 会先扩容(全部搬迁)再后移;
  • erase :
    • 返回指向下一个迭代器
    • 所有后面整体元素前移 O(n)
    • 可以依靠返回的迭代器配合2.3.4remove()unique() 使用
c++
iterator insert(pos, val);           // 在 pos 插入
iterator erase(pos);                 // 删单个
iterator erase(first, last);         // 删区间

v.insert(v.begin()+2, 99);           // 下标 2 处插入 99
v.erase(v.end()-2);                  // 删倒数第二个

// 惯用套路: 删全部等于 key 的元素(erase-remove)
v.erase(remove(v.begin(), v.end(), key), v.end()); 

// 去重套路: 
v.erase(unique(v.begin(),v.end()), v.end());

2.3.5 remove & unique


  • 这是很多初始者一开始产生疑惑的地方,uniqueremove<algorithm> 里的一对 “ 假象兄弟 ”:
    • 都不真正删除对象(不缩小容器 size
    • 都只负责把 “好元素” 紧凑到前面,然后返回一个 new_end 迭代器
    • 都必须再手动 erase 才能完成 “物理删除”
    • 复杂度都是 O(n),额外空间 O(1)

  • 两者区别在于 “ 判定好坏的标准 ”
算法保留规则典型用途需不需要相邻
remove值 != key按值删除不需要相邻
unique相邻且相等去重必须相邻

  • 📌 注意:使用 unique 的关键点:

    算法本质是(快慢)双指针,所以必须要相邻并且相等才能正确比较,

    所以在使用之前 必须要进行排序 ,这样才能把 “全局重复” 变成 “相邻重复”


  • remove 示例代码:
c++
#include <iostream>
#include <vector>     
#include <algorithm>

using namespace std;

int main()
{
    vector<int> nums = {5,7,3,7,8,7};
    
    // remove {key = 7}
    // 初始 {5,7,3,7,8,7} → 整理后 {5,3,8,?,?,?} → erase 后 {5,3,8}
    
    // remove(nums.begin(),nums.end(),7); // 按值(逻辑)remove
    
    // for(int x : nums) cout << x << ' '; // 5 3 8 7 8 7 
    // 可以发现只是把 不删除的元素移到了前面, 没有改变 size, 那么后面一段将会是脏数据
    
    // 利用返回值 erase : 删除 new_end 到 end 的尾部垃圾
    // 那么就可以实现对原 vector 删除一个或多个指定 key 的操作
    nums.erase(remove(nums.begin(),nums.end(),7), nums.end());  // 5 3 8
    for(int x : nums) cout << x << ' ';

    return 0;
}

  • unique 示例代码:
c++
#include <iostream>
#include <vector>     
#include <algorithm>

using namespace std;

int main()
{
    vector<int> nums = {1,1,2,2,2,3,4,4};
    
    // 初始 {1,1,2,2,2,3,4,4} → 整理后 {1,2,3,4,?, ?, ?, ?} → erase 后 {1,2,3,4}
    // 如果未排序 {1,2,1,2} → unique 后 {1,2,1,2}(一个也没去掉)
    
    // 必须先排序 !!
    sort(nums.begin(), nums.end());
    
    // 查看排序好的序列
    for(int x: nums) cout << x << ' '; // 1 1 2 2 2 3 4 4
    cout << endl;
    
    // 去重
    nums.erase(unique(nums.begin(),nums.end()), nums.end());
    
    // 查看去重后的序列
    for(int x: nums) cout << x << ' '; // 1 2 3 4 

    return 0;
}

2.3.6 常用算法搭档


  • 需要头文件
c++
#include <algorithm>

c++
sort(v.begin(), v.end());                    // 升序
sort(v.rbegin(), v.rend());                  // 降序
binary_search(v.begin(), v.end(), value);    // 二分查找: (升序可用), 返回是否存在
lower_bound(v.begin(), v.end(), value);		// 二分查找: 返回第一个大于等于value的迭代器
upper_bound(v.begin(), v.end(), value);		// 二分查找: 返回第一个大于value的迭代器
find(v.begin(), v.end(), value);   			// 返回查找元素的迭代器
reverse(v.begin(), v.end());				 // 翻转

2.3.7 支持比较运算


c++
// 支持比较运算(字典序)
vector<int> d(3,4),  e(4,3);
// d: 4 4 4;  e: 3 3 3 3
cout << (d < e) << endl;  // 0
cout << (d > e) << endl;  // 1

2.4 键值对 pair


2.4.1 概述


  • 接下来了解一个非常常用的轻量级的模板类 pair,它用于将两个值组合成一个对象,

    常用于函数返回多个值、容器(如 std::map )中存储键值对等场景。

  • 联想:它像不像当我们想用一个具有两个属性的结构体的简易替换

  • 思路打开:不止可以存储两个,比如存储三个 pair<int,pair<int,int>>


c++
#include <utility>  // 其它头文件也会包含 pair
std::pair<T1, T2> p;
  • T1T2 可以是任意类型(基本类型、类、容器等)。
  • pair 有两个公有成员:firstsecond

  • 基本操作:
操作示例
创建make_pair(11,"irai")
访问p.firstp.second
修改p.first = 10;
比较p1 < p2

2.4.2 创建 &初始化


c++
#include <iostream>

using namespace std;

int main()
{
    // 方法1:默认构造
    pair<int, string> p1;
    p1 = {18, "irai"};

    // 方法2:直接初始化
    pair<int, string> p2(42, "irai");

    // 方法3:使用 make_pair(自动推导类型)
    auto p3 = make_pair(3.14, 'A');

    // 方法4:列表初始化(C++11)
    pair<int, double> p4{1, 2.5};
    
    return 0;
}

2.4.3 访问元素


c++
pair<int, string> p(11, "irai");
cout << p.first << ' ' << p.second << endl; // 11 irai

2.4.4 修改元素


c++
p.first = 20;
p.second = "world";

2.4.5 比较操作


  • 支持比较运算符(==, !=, <, <=, >, >=),按字典序比较(先比 first,再比 second):
c++
pair<int, int> a(1, 2);
pair<int, int> b(1, 3);

bool result = a < b;  // true,因为 first 相等,second 2 < 3

2.5 string


2.5.0 概览


  • 常用操作
操作行为
size() / length()返回字符串长度
empty()判空
clear()清空字符串
substr(起始下标, (子串长度))返回子串
c_str返回字符串所在字符数组的起始地址

2.5.1 构造 / 赋值


c++
// 1. 空串
string s1;

// 2. 用 C-string 构造
string s2("hello");

// 3. 重复字符
string s3(8, '*');          // ********

// 4. 用另一个 string 构造(拷贝)
string s4(s2);

// 4. 用迭代器区间构造
string s5(s2.begin(), s2.begin()+3);  // "hel"

// 6. 赋值运算符
s1 = "world";
s1 = s2;

2.5.2 大小 & 容量


c++
string s = "abcdef";
s.size();      // 6  O(1)
s.length();    // 6  完全等价 size()
s.empty();     // false
s.capacity();  // 当前已申请的内存,≥size()
s.reserve(100);// 提前扩容, 避免后续频繁 realloc
s.shrink_to_fit(); // C++11,请求缩容(非强制)

2.5.3 元素访问


c++
string s = "hello";
s[0]   = 'H';        // (不安全但好用) 不检查越界
s.at(0) = 'H';       // (安全) 越界抛 std::out_of_range
s.front() = 'H';     // C++11
s.back()  = 'O';     // C++11

2.5.4 修改


c++
// 4.1 追加
string s = "a";
s += "b";                // "ab"
s.push_back('c');        // "abc"
s.append(3, 'd');        // "abcddd"
s.append("xyz", 2);      // "abcdddxy"  (只取前 2 字符)

// 4.2 插入
string s = "ace";
s.insert(1, "B");        // "aBce"  (pos, string)
s.insert(s.begin() + 2, 'C'); // "aBCce"

// 4.3 删除
s.erase(2, 2);           // 从 pos=2 开始删 2 字符
s.pop_back();            // C++11,删最后一个

//4.4 替换
string s = "I have a book";
s.replace(7, 6, "a pen");  // "I have a pen"

//4.5 清空
s.clear();               // 秒变空串,容量不变

2.5.5 查找


c++
string s = "hello world hello";
s.find("lo");            // 3  (第一次出现)
s.rfind("lo");           // 15 (最后一次出现)
s.find("abc");           // string::npos  (不存在)
s.find_first_of("aeiou"); // 1  ('e') 找 s 第一个出现的字母
s.find_last_of("aeiou");  // 7  ('o') 找 s 最后一个出现的字母
s.find_first_not_of("he"); // 2  ('l')	找 s 第一个没有的字母

2.5.6 比较


c++
string a = "apple", b = "banana";
a == b;                  // false
a != b;                  // true
a < b;                   // true  (字典序)
a.compare(b);            // <0  (等价于 strcmp)
a.compare(0, 3, b, 0, 3); // 比较子串 "app" vs "ban"

2.5.7 截取


c++
string s = "abcdef";
// substr(哪个下标开始, 几个字符)
string sub = s.substr(2, 3); // "cde"  (pos, count)

2.5.8 数字转换 (c++11)


c++
string s1 = to_string(123);     // "123"
string s2 = to_string(3.1415);  // "3.141500"

2.5.9 遍历


c++
string s = "hello";
for (auto it = s.begin(); it != s.end(); ++it) *it = toupper(*it);
// 现在 s == "HELLO"
// C++11 范围 for
for (char &c : s) c = tolower(c);  // 又变回 "hello"

2.5.10 转字符数组


c++
string s = "hello";
const char* p = s.c_str(); // 返回 '\0' 结尾的 const char*
printf("%s", p); // hello

2.5.11 常用算法


c++
string s = "31415926";
reverse(s.begin(), s.end());           // "92695141"
sort(s.begin(), s.end());              // "11245699"
auto it = find(s.begin(), s.end(), '5'); // 返回查找到的迭代器

// 原地修改s为下一个排列,返回有无这样的排序的bool值
bool ok = next_permutation(s.begin(), s.end());
  • 补充:std::next_permutationC++ 标准库 <algorithm> 中的一个函数,

    用于 原地 将序列变换为字典序的下一个排列。如果存在这样的排列,返回 true

    否则将序列变换为字典序最小的排列(即升序),并返回 false


2.5.12 拼接大量小片段


c++
// 糟糕:频繁 realloc
string bad;
cout << bad.capacity(); // 0
for (int i = 0; i < 1e5; ++i) bad += "x";

// 推荐:先 reserve
string good;
good.reserve(1e5);
cout << good.size() << endl; // 0
cout << good.capacity() << endl; //102343
for (int i = 0; i < 1e5; ++i) good += "x";

2.6 queue


  • 普通队列: queue : 先进先出
c++
// 头文件
#include <queue>

  • 常用操作:
c++
// 构造
queue<T> q;		// 一般
queue<int> q;	// int 为元素
struct rec{…}; queue<rec> q;	// 结构体为元素

q.size()	// 大小
q.empty()		// 判空
    
q.push(x);	// 向队尾插入一个元素
q.pop()  	// 弹出队头元素
    
q.front()  	// 	返回队头元素
q.back()  	//	返回队尾元素

2.7 priority_queue


  • 优先队列(堆):priority_queue
c++
// 头文件
#include <queue>

  • 构造:
c++
// 构造
priority_queue<int> q;                              // 大根堆
priority_queue<int, vector<int>, greater<int>> q;   // 小根堆
struct rec{…}; priority_queue<rec> q; 		// 结构体 rec 中必须定义小于号
priority_queue<pair<int, int>>q;		// pair 默认先比较 first 再比较 second
  • 补充:std::priority_queue 默认使用 std::less<T> 作为比较规则,

    也就说它会按 “<” 语义 建 大根堆(看上去 “大的排在前面” )。

    • ❓ ​疑惑:大根堆明明是大的在堆顶,为什么要用小于号作比较规则

      解释:一个比较函数 若 comp(a,b)==truea 的优先级低于 b

      默认比较器是 std::less,即 comp(a,b) = (a < b)

      那么 当 a < b 为真时,比较器说 “ a 优先级低于 b ”,于是 b 会往堆顶走。

    • 📌 ​更好的理解方式:这一点我发现有点像 冒泡排序

      当我们写冒泡排序的时候,如果要写一个 降序 的,那么比较函数就是

      c++
      bool comp(int a, int b){
          if(a < b) return true;
          else return false;
      }
      
      //冒泡排序中: 
      	// 如果 a 小于 b 则 swap , 也就是小的数a去后面
      	if(comp(a,b)) swap(a,b);

      最后出来的效果是 降序 , 那看起来不就像 大根堆 那样,大的数在前面吗

      然后我们看一下我们写的比较函数,不就是利用 < 实现的比较规则吗!!

    • 重载比较符号:

    c++
    struct Node {
        int val;
        // 大根堆:值大的优先级高(小于号比较: 小的数去后面)
        bool operator<(const Node& rhs) const {
            return val < rhs.val;   // 注意这里是“小于”
        }
    };
    • 小根堆的写法:
    c++
    // 1. 构造函数中换比较器
    priority_queue<int, vector<int>, greater<int>> q;
    
    
    // 2. 重载比较运算符
    bool operator>(const Node& a, const Node& b) {
        // (大于号比较: 大的数去后面 -- 小根堆)
        return a.val > b.val;   // 值越小优先级越高
    }
    
    // 3. 自定义比较器
    auto cmp = [](const Node& a, const Node& b) {
        // (大于号比较: 大的数去后面 -- 小根堆)
        return a.val > b.val;   // 返回 true 表示 a 优先级低于 b → 小值上浮
    };
    std::priority_queue<Node, std::vector<Node>, decltype(cmp)> pq(cmp);

  • 三个核心操作:
c++
push(x);    // 把元素插入堆
pop();     	// 删除堆顶元素
top();     	// 查询堆顶元素(最大值)

2.8 stack


  • 默认基于 std::deque 封装而成, 先进后出 的特点

  • 头文件:

c++
#include <stack>

  • 定义:
c++
stack<int> s;  // 默认使用 deque 作为底层容器

也可以指定底层容器(如 vectorlist):

c++
stack<int, vector<int>> s;

  • 常用操作:
操作说明
push(x)将元素 x 压入栈顶
pop()移除栈顶元素(不返回值)
top()返回栈顶元素的引用
empty()判断栈是否为空
size()返回栈中元素个数

2.9 哈希表


  • C++ STL 里的 “哈希表” 就是无序关联容器(C++11 起引入), 共四个模板:
容器名键唯一能否重复键头文件
unordered_map唯一<unordered_map>
unordered_multimap可重复<unordered_map>
unordered_set唯一<unordered_set>
unordered_multiset可重复<unordered_set>

  • 用法 95% 与 map/set 相同,只是 内部红黑树 → 哈希表 ,接口多了“桶”相关函数。

    下面以 unordered_map 为例,列出常用操作。


  • 1). 增 / 改 / 查
c++
unordered_map<string,int> mp;

mp["Bob"] = 18;              // 插入或覆盖
mp.insert({"Alice",20});     // 仅当 key 不存在才插入
mp.emplace("Tom",19);        // 原位构造,少一次拷贝

auto it = mp.find("Bob");    // 找不到返回 mp.end()
if (it != mp.end()) cout << it->second;

int age = mp.at("Alice");    // key 不存在抛 std::out_of_range

int age2 = mp["Carol"];      // 不存在会默认构造 value(int 为 0)
// 也就是 age 2 为 0 的同时,mp 插入了一份 {"Carol" : 0}

  • 2). 删
c++
mp.erase("Bob");             // 按 key 删, 返回删除个数 0/1
mp.erase(it);                // 按迭代器删,O(1) 均摊
mp.clear();                  // 清空

  • 3). 大小 & 判空
c++
mp.size();                   // 元素个数
mp.empty();                  // 是否空

  • 4). 遍历
c++
// for 范围遍历
for(auto x : mp){
    cout << x.first << ' ' << x.second << endl;
}

// 迭代器遍历
for(auto it = mp.begin(); it != mp.end(); it ++ ){
    cout << it->first << ' ' << it->second << endl;
}
  • ❓ 为什么一个用 . 一个用 ->

    • 范围 for 拿到的 x 是容器中 "元素" 的一份拷贝, 即 pair<string,int>

      所以使用的是 对象的成员选择运算符 .

    • 迭代器遍历中的 it 是指向元素的指针,所以使用 指针的成员选择运算符 ->

    • 如果说 auto& x : mp 拿到的 x 就是加了一份引用,内部不会拷贝


  • 5). 当 key 不是内置类型时,需要自己写哈希函数和相等比较:
    • 哈希函数 —— 告诉哈希表 “怎么把 ’元素‘ 散列到桶里” ;
    • 相等比较 —— 告诉哈希表 “怎么判断两个 ‘元素‘ 相同” 。
c++
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

struct Point{
    int x, y;

    // 1. 重载相等
    bool operator==(const Point& t) const{
        return x == t.x && y == t.y;
    }
};

// 2. 独立的哈希器
struct PointHash {
    size_t operator()(const Point& p) const noexcept {
        // 下面这一行就是“哈希函数”的全部工作:把两个整数映射成一个 size_t
        return hash<int>{}(p.x) ^ (hash<int>{}(p.y) << 1);
    }
};

int main()
{
    unordered_map<Point, int, PointHash> mp; // 第三个模板实参传哈希器
    mp[{1, 2}] = 42;
    cout << mp[{1, 2}] << endl; // 42
    return 0;
}

  • 6). 返回某个元素个数
c++
mp.count({1,2});	// 返回 {1,2} 的个数

// 更多是在 unordered_set : 个数就是 1/0 , 那么我们可以判断某个数在不在 set
unordered_set<int> s;
s.insert(1);
s.insert(1);
cout << s.count(1) << endl;		// 1
cout << s.count(10) << endl;	// 0