GESP7级C++考试语法知识(四、哈希表(7、unordered_set)


第七课:《魔法通讯录------认识 unordered_set》


一、调查队的新任务

1、经过上一课的学习。

🕵️ 失踪宝石调查队已经学会了:

复制代码
unordered_map

可以快速判断:

复制代码
某个东西是否存在

2、有一天。

国王又发布了一项新任务:

"请记录所有进入城堡的人!"


名单如下:

复制代码
Tom
Jack
Mike

3、国王继续问:

"Tom来过吗?"

"Jack来过吗?"

"Alice来过吗?"


智慧大臣突然发现:

这里根本不需要分数。

不需要年龄。

不需要电话。


4、只需要知道:

复制代码
来过
或者
没来过

于是。

他拿出了一个新法宝:

🏆 unordered_set


二、为什么要发明 unordered_set?

1、先看看 unordered_map。


例如:

复制代码
unordered_map<string,int> mp;

mp["Tom"] = 1;
mp["Jack"] = 1;
mp["Mike"] = 1;

这里:

复制代码
Key   → 姓名

Value → 1

2、问题来了。


这个:

复制代码
= 1

真的有意义吗?


其实没有。


我们根本不关心:

复制代码
1

是多少。


只关心:

复制代码
Tom在不在

3、所以。

聪明的程序员说:

"既然Value没用。"

"那干脆不要Value了!"


4、于是:

unordered_set 诞生了


三、什么是 unordered_set?

1、可以把它理解成:

只有 Key 的哈希表


2、unordered_map:

复制代码
Tom → 95

Jack → 88

Mike →100

3、unordered_set:

复制代码
Tom

Jack

Mike

4、只保存数据本身。


没有:

复制代码
95
88
100

这些Value。


四、创建通讯录

1、代码:

复制代码
#include <iostream>
#include <unordered_set>
using namespace std;

int main()
{
    unordered_set<string> s;
}

2、这里:

复制代码
unordered_set<string>

表示:

复制代码
存储字符串集合

3、例如:

复制代码
Tom

Jack

Mike

五、添加联系人

1、通讯录刚开始是空的。


添加:

复制代码
s.insert("Tom");

通讯录:

复制代码
Tom

2、继续:

复制代码
s.insert("Jack");
s.insert("Mike");

变成:

复制代码
Tom

Jack

Mike

六、insert是什么意思?

1、insert 翻译:

复制代码
插入

2、例如:

复制代码
s.insert("Tom");

意思:

复制代码
把Tom放进集合

七、查询联系人

1、国王问:

"Tom来过吗?"


代码:

复制代码
s.count("Tom")

2、结果:

复制代码
1

表示:

复制代码
存在

3、国王又问:

"Alice来过吗?"


代码:

复制代码
s.count("Alice")

4、结果:

复制代码
0

表示:

复制代码
不存在

八、最常见写法

复制代码
if(s.count("Tom"))
{
    cout << "存在";
}
else
{
    cout << "不存在";
}

输出:

复制代码
存在

九、神奇的去重能力

1、通讯录管理员发现一个问题。


(1)Tom连续登记三次:

复制代码
s.insert("Tom");
s.insert("Tom");
s.insert("Tom");

(2)通讯录会变成:

复制代码
Tom
Tom
Tom

吗?


(3)答案:

❌ 不会


(4)结果仍然是:

复制代码
Tom

2、因为:

set 天生不允许重复


这是它最强大的能力之一。


十、为什么叫集合?

1、数学课学过:

复制代码
集合

(1)例如:

复制代码
{1,2,3}

(2)里面:

复制代码
1

只能出现一次。


(3)不会出现:

复制代码
{1,1,1,2,3}

2、所以:

复制代码
unordered_set

本质就是:

复制代码
哈希集合

十一、自动去重演示

1、代码:

复制代码
unordered_set<int> s;

s.insert(5);
s.insert(5);
s.insert(5);
s.insert(5);

2、最终集合:

复制代码
5

只有一个。


十二、统计有多少种不同数字

1、这是竞赛中的经典题。


(1)输入:

复制代码
1 5 2 1 3 5 5 2

(2)问题:

复制代码
共有多少种不同数字?

(3)我们看:

复制代码
1
2
3
5

(4)答案:

复制代码
4种

2、程序怎么做?


(1)建立集合:

复制代码
unordered_set<int> s;

(2)每读一个数字:

复制代码
s.insert(x);

(3)过程:

复制代码
1

1 5

1 5 2

1 5 2

1 5 2 3

1 5 2 3

1 5 2 3

1 5 2 3

(4)重复数字自动消失。


(5)最后:

复制代码
cout << s.size();

(6)输出:

复制代码
4

十三、size()是什么?

复制代码
s.size()

1、表示:

复制代码
集合中元素个数

2、例如:

复制代码
unordered_set<int> s;

s.insert(1);
s.insert(2);
s.insert(3);

(1)此时:

复制代码
cout << s.size();

(2)输出:

复制代码
3

十四、完整实例

1、统计不同数字个数。

复制代码
#include <iostream>
#include <unordered_set>
using namespace std;

int main()
{
    int n;

    cin >> n;

    unordered_set<int> s;

    for(int i=0;i<n;i++)
    {
        int x;
        cin >> x;

        s.insert(x);
    }

    cout << s.size();

    return 0;
}

2、输入:

复制代码
8

1 5 2 1 3 5 5 2

3、输出:

复制代码
4

十五、unordered_map 和 unordered_set 对比


1、unordered_map

保存:

复制代码
Key → Value

例如:

复制代码
Tom → 95

Jack → 88

创建:

复制代码
unordered_map<string,int> mp;

适合:

复制代码
统计次数

姓名查分数

学号查姓名

2、unordered_set

保存:

复制代码
只有Key

例如:

复制代码
Tom

Jack

创建:

复制代码
unordered_set<string> s;

适合:

复制代码
判断存在

查重

统计不同元素

十六、什么时候用哪个?

记住一句口诀:


1、如果需要:

复制代码
姓名 → 分数

数字 → 次数

用:

复制代码
unordered_map

2、如果只需要:

复制代码
在不在?

用:

复制代码
unordered_set

十七、比赛中的高频应用

1、以后看到:

复制代码
有多少种不同数字

是否重复

是否访问过

单词是否出现过

用户名是否注册过

2、第一反应:

复制代码
unordered_set

十八、小试牛刀

1、集合:

复制代码
unordered_set<int> s;

s.insert(3);
s.insert(5);
s.insert(3);
s.insert(8);

2、问题1:

集合里有哪些数字?


答案:

复制代码
3
5
8

3、问题2:

有几个数字?


答案:

复制代码
3

4、问题3:

复制代码
s.count(5)

结果是多少?


答案:

复制代码
1

5、问题4:

复制代码
s.count(10)

结果是多少?


答案:

复制代码
0

本课总结

1、今天认识了哈希表家族的重要成员:

🏆 unordered_set


2、创建:

复制代码
unordered_set<int> s;

3、插入:

复制代码
s.insert(x);

4、判断存在:

复制代码
s.count(x)

5、统计元素个数:

复制代码
s.size()

6、最大特点:

复制代码
自动去重

经典模板

1、判断是否存在:

复制代码
if(s.count(x))
{
    cout << "存在";
}

2、统计不同数字:

复制代码
unordered_set<int> s;

for(int i=0;i<n;i++)
{
    int x;
    cin >> x;

    s.insert(x);
}

cout << s.size();

魔法口诀

复制代码
通讯录里记名字,

不用分数不用值。

insert负责来登记,

count负责来查询。

重复名字自动删,

去重能力最领先。

统计不同最拿手,

unordered_set真优秀!

下一课我们将进入哈希表经典的实战关卡:

《谁偷了国王的金币------查重问题》

你会学到很多竞赛高手最喜欢的技巧:

复制代码
if(s.count(x))

一眼发现重复数字!