> 文章列表 > 学会吊打面试官之set

学会吊打面试官之set

学会吊打面试官之set

 

小白:大牛,我最近在学习C++的STL容器,发现set好像是一种比较特殊的容器,可以帮我简单介绍一下吗?

大牛:没问题,set是一种关联式容器,它的主要特点是不允许有重复元素,并且元素是有序的。

小白:不允许有重复元素?那和数组或者向量有什么区别呢?

大牛:数组和向量都是顺序容器,允许有重复元素,而set则是关联式容器,它的内部实现是基于红黑树的,因此在插入、删除元素时都有比较高的效率。

小白:那我该如何使用set呢?

大牛:set有两个常用的操作:插入元素和查找元素。你可以使用insert函数插入元素,使用find函数查找元素。

下面给你一个例子,我们定义一个set来存储一组学生的分数,然后插入几个分数,最后查找一个分数是否在set中。

#include <iostream>
#include <set>using namespace std;int main()
{set<int> scores; // 定义一个set来存储分数// 插入几个分数scores.insert(85);scores.insert(72);scores.insert(93);scores.insert(68);scores.insert(78);// 查找一个分数是否在set中if (scores.find(85) != scores.end()) {cout << "85分在set中" << endl;} else {cout << "85分不在set中" << endl;}return 0;
}

小白:我看到你在代码里用了scores.end(),这是什么意思呢?

大牛:end()函数返回的是set中最后一个元素之后的位置,它通常用于表示一个不存在的元素。在上面的例子中,如果85分不存在于set中,那么scores.find(85)将返回scores.end(),从而判断85分不在set中。

小白:原来如此,set真的很方便啊,不过我还有一个问题,set的底层实现是什么?

大牛:set的底层实现是基于红黑树,它是一种自平衡的二叉查找树,可以在O(log n)的时间内完成插入、删除、查找等操作。你可以自己实现一下红黑树来加深理解。

小白:好的,我会去看看红黑树的实现,谢谢你的讲解。

大牛:不客气,有问题可以随时问我。

小白:那set和map有什么区别呢?

大牛:set和map都是关联容器,但是set中存储的是一组不重复的元素,而map则是键值对的集合,每个键值对都是独一无二的。

小白:明白了!那我们来看看set的使用场景吧。

大牛:set通常用于需要快速查找、插入和删除元素的情况。比如,你想要对一个列表进行去重操作,就可以使用set来实现。

小白:噢,那我可以用set来实现这个功能了。请问,set的实现原理是什么呢?

大牛:set的底层实现通常是基于平衡二叉树(比如红黑树)或者哈希表。对于平衡二叉树实现的set,查找、插入和删除的时间复杂度都是O(log n),而哈希表实现的set,这些操作的时间复杂度通常是O(1)。

小白:这样啊,看来使用set还是挺方便的。你能给我举个例子吗?

大牛:当然可以。假设你有一个字符串列表,需要对其中的重复字符串进行去重操作,代码如下:

#include <iostream>
#include <set>
#include <string>int main() {std::set<std::string> mySet;std::string str;while (std::cin >> str) {mySet.insert(str);}for (const auto& s : mySet) {std::cout << s << " ";}std::cout << std::endl;return 0;
}

这个程序会不断从标准输入中读取字符串,然后将其插入到set中。由于set会自动去重,所以最终只会输出不重复的字符串。

小白:太厉害了!看来set真的很实用。

大牛:是的,set和其他STL容器一样,提供了丰富的操作和算法,可以让我们更加方便地处理数据。

大牛:没问题,这个例子我来给你举一个更加具体的应用场景。假设我们有一个学生名单,里面存储着所有选修了某一门课程的学生的学号,现在我们要求出选修这门课的学生数量。

小白:好的,那我们该怎么做呢?

大牛:我们可以使用set来存储所有选修这门课的学生学号,因为set具有不重复的特性,所以存储学号的时候不会出现重复的情况。

小白:明白了,那我们该怎么使用set呢?

大牛:首先,我们需要定义一个set对象,可以这样写:

std::set<int> studentSet;

这个定义语句表示我们定义了一个存储int类型数据的set对象,名字叫做studentSet。

接下来,我们需要将所有选修了这门课程的学生的学号加入到这个set对象中,可以使用insert函数来实现:

studentSet.insert(10001);
studentSet.insert(10002);
studentSet.insert(10003);

这些代码表示我们将学号为10001、10002和10003的学生加入到了set对象中。

最后,我们只需要使用size函数来获取set对象中元素的数量就可以了:

std::cout << "选修这门课的学生数量为:" << studentSet.size() << std::endl;

小白:哇,这个例子非常好理解,我觉得我已经掌握了set的使用方法了。但是,我还有一个问题,set是如何实现的呢?

大牛:set是使用红黑树来实现的,这也是set具有自动排序和去重功能的原因。红黑树是一种自平衡的二叉搜索树,具有良好的插入、删除和查找性能。

小白:原来如此,谢谢大牛的解答,我学到了很多新的知识!

大牛:不客气,希望你能在以后的工作中有所收获!

大牛:set底层使用红黑树实现,这是一种自平衡二叉查找树,可以保证插入、删除、查找等操作的时间复杂度都是O(log n)。所以,当需要高效率的查找、插入、删除时,set是一个不错的选择。

小白:那我平常怎么会用到set呢?

大牛:set的应用场景很多,比如去重、排序、查找等。举个例子,假设你要对一篇文章中的单词进行去重操作,那么可以使用set来存储这些单词,因为set会自动去重,而且可以在插入的同时进行排序。

小白:哦,我懂了。你能再举个例子吗?

大牛:当然可以。比如说你要在一组数据中查找出不重复的元素,可以使用set来实现。具体代码如下:

#include <iostream>
#include <set>
using namespace std;int main() {int arr[] = {1, 2, 3, 4, 3, 2, 5, 6, 4, 7};int n = sizeof(arr) / sizeof(arr[0]);set<int> s;for (int i = 0; i < n; i++) {s.insert(arr[i]);}for (auto x : s) {cout << x << " ";}return 0;
}

这段代码中,我们使用set来存储arr数组中的元素,并且自动去重和排序。最后,我们遍历set中的元素,输出不重复的结果。

小白:哇,这个例子好棒啊!我明白了,set真的很方便呢。