笔者最近在找工作时,无意间读到了一本名为《剑指offer》的书,粗略翻阅了一下,感觉这将会是一本能让我不再苦恼于笔试和面试“手搓代码”的书。故笔者写下该系列博客记录自己的学习历程,希望能和这本书的读者朋友们一起交流学习心得。
介绍:《剑指Offer:名企面试官精讲典型编程题(第2版)》剖析了80个典型的编程面试题,系统整理基础知识、代码质量、解题思路、优化效率和综合能力这5个面试要点。
编程题链接:牛客网在线编程_算法面试_面试必刷TOP101 (nowcoder.com)
本篇参考博客:C++总结(7):STL无序容器之unordered_set、unordered_map、unordered_multiset、unordered_multimap详解_无序互异容器-优快云博客
本博客关键词:unordered_set和unordered_map
unordered_set
无序集合unordered_set
是C++标准模板库(STL)中的一个关联容器,用于存储唯一的元素,并以哈希表为底层实现。它与set
的主要区别在于元素的存储顺序:unordered_set
是无序的,依赖于哈希表来快速查找、插入和删除元素。
无序集合unordered_set
的几个性质:
- 无序性:元素按照哈希表的方式存储,而不是按照插入顺序或大小顺序;迭代遍历时,元素输出顺序是不确定的。
- 唯一性:
unordered_set
中不允许有重复的元素。如果尝试插入已经存在的元素,新插入的操作将无效,且原来的元素不会被更改。 - 高效性:查找、插入、删除的平均时间复杂度是
O(1)
,但是在最坏的情况下(严重哈希冲突),时间复杂度会达到O(n)
。 - 元素不可改:插入的元素不能在集合中修改,如果想修改得先删除再插入新元素。
常用方法
size()
和empty()
:用于获取大小和集合是否为空insert()
和erase()
:用于插入和删除元素find()
:用于查找值(unordered_set
中的元素既是值也是键,有别于unordered_map
)
测试用例
#include <iostream>
#include <unordered_set>
using namespace std;
int main(int argc, char const *argv[])
{
unordered_set<string> stringset;
// 插入元素
stringset.insert("this");
stringset.insert("is");
stringset.insert("a");
stringset.insert("C++");
stringset.insert("demo");
// 判断集合是否为空
if (stringset.empty())
{
cout << "无序集合为空" << endl;
return -1;
}
else // 不为空则输出集合大小
{
cout << "集合的大小是:" << stringset.size() << endl;
}
// 查找
if (stringset.find("C+") != stringset.end())
{
cout << "找到了对应的元素" << endl;
}
else
{
cout << "没有找到对应的元素" << endl;
}
stringset.insert("demo"); // 无法重复插入
stringset.insert("demo1"); // 成功插入
cout << "集合的大小是:" << stringset.size() << endl;
// 遍历元素
unordered_set<string>::iterator itr;
for (itr = stringset.begin(); itr != stringset.end(); itr++)
{
cout << (*itr) << " ";
}
cout << endl;
return 0;
}
unordered_map
无序映射unordered_map
是C++标准模板库(STL)中的一个关联容器,用于存储键-值对(key-value pairs)。键值用于唯一标识元素,而映射值是与键相关联的内容。键和值都可以是任何预定义或用户定义的类型。unordered_map
基于哈希表实现,因此可以提供高效的查找、插入和删除操作。
无序映射unordered_map
的几个性质:
- 无序性:
unordered_map
中的元素不是按照键的大小顺序存储的,而是基于哈希表的方式进行存储。 - 键值对存储:其中键(key)是唯一的,而值(value)可以是任意类型;如果插入一个已经存在的键,其对应的值将被更新为新值。
- 高效性:查找、插入、删除的平均时间复杂度是
O(1)
,但是在最坏的情况下(严重哈希冲突),时间复杂度会达到O(n)
。跟unordered_set
一样。 - 元素访问:
at(key)
:如果键存在,则返回对应值;如果键不存在,会抛出std::out_of_range
异常。operator[]
:如果键存在,则返回对应值;如果键不存在,则会插入一个具有默认值(int类型对应默认值为0)的元素并返回其引用。
常用方法
insert()
:插入一个键-值对。如果键已存在,不会插入新的元素。示例:map.insert(make_pair("java", 40));
erase()
:删除指定键的元素。find()
:查找指定键的元素,返回指向该元素的迭代器;如果未找到,返回end()
迭代器。size()
和empty()
:用于获取大小和判断无序映射是否为空
测试用例
#include <iostream>
#include <unordered_map>
using namespace std;
int main(int argc, char const *argv[])
{
unordered_map<string, int> map;
map["C++"] = 10;
map["C"] = 20;
map["python"] = 30;
if (map.empty())
{
cout << "无序映射为空" << endl;
}
else
{
cout << "无序映射不为空,且大小为:" << map.size() << endl;
}
// 返回键对应的值的引用,如果键不存在会抛出异常
cout << map.at("C++") << endl;
// 插入元素
map.insert(make_pair("java", 40));
map.insert(make_pair("python", 100)); // 不会插入已有键
// 键不存在,自动插入默认值
cout << "operator[]:" << map["C#"] << endl;
if (map.find("java") != map.end())
{
cout << "值存在" << endl;
}
else
{
cout << "值不存在" << endl;
}
// 删除指定键值对
map.erase("C++");
// 遍历无序映射
for (auto x : map)
{
cout << x.first << "=" << x.second << " ";
}
cout << endl;
return 0;
}