引子:
时隔多日,我又回来啦,接上回,我们讲到set的一小部分,我们今天来讲详细讲set与map,满满干货启动!根据应用场景的不同,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。
扩展:序列的稳定性:在稳定的排序算法中,如果两个元素的值相等,它们在排序后的位置与排序前的相对顺序保持不变。例如,冒泡排序和插入排序是稳定的排序算法,而快速排序、选择排序和堆排序则是不稳定的。
pair的引入:
pair是C++ STL中定义的一个模板类,用于存储一对值,
用途:pair
常用于函数返回两个值的场景,或者作为键值对存储在某些容器中
pair
对象支持比较操作符,如==
, !=
, <
, >
, <=
, >=
,这些操作符首先比较.first
成员,如果相等,则比较.second
成员
成员访问:pair
对象提供了访问其两个元素的方法,通常使用.first
和.second
来分别访问第一个和第二个元素
对于set来说为pair<迭代器,bool>,对于map来说是pair<key,value>
set利用pair.second的:判断带环链表的入环点或是否带环等问题
map利用pair对应的second,可以做英文字典的查找,门禁卡等工作
什么是set?
总的来说有以下几点:
-
元素唯一性:set中的每个元素都是唯一的,不允许重复。如果尝试添加一个已经存在的元素,大多数情况下,这个操作会被忽略。
-
无序性:虽然你提到了"按照一定次序存储元素",但实际上大多数编程语言中的set并不保证元素的存储顺序。它们通常不按照元素的添加顺序或任何特定的顺序来存储元素。
-
元素作为键:在某些编程语言中,如C++的
std::set
,元素既是键也是值,因为set是基于键值对的集合,但键和值是相同的。 -
不可修改性:set中的元素通常是不可修改的,即一旦元素被添加到set中,就不能更改它的值。但是,你可以删除元素,然后重新插入一个新的元素。
-
基于红黑树的实现:在某些实现中,set可能使用红黑树来维护元素的有序性,这允许set在对数时间内进行查找、插入和删除操作。但是,并非所有set的实现都使用红黑树,有些可能使用哈希表。
-
类型为T:set可以存储任何类型的元素,只要这些元素支持比较操作,以便确定它们在set中的顺序(在基于红黑树的实现中)。
-
常量元素:在某些语言中,set中的元素被视为常量,意味着你不能更改它们,但可以添加或删除。
set的一些常用函数:
-
empty()
:检查集合是否为空。 -
size()
:返回集合中元素的数量。 -
clear()
:移除集合中的所有元素。 -
insert(value)
:向集合中插入一个新的元素。如果元素已存在,则不执行插入操作。 -
erase(value)
:从集合中删除特定的元素。也可以删除指定范围内的元素。 -
find(value)
:查找集合中是否存在特定值的元素,如果存在,返回指向该元素的迭代器;如果不存在,返回end()
迭代器。 -
count(value)
:返回集合中具有特定值的元素数量,对于set
,这个函数总是返回0或1。 -
lower_bound(value)
:返回指向大于或等于指定值的第一个元素的迭代器。 -
upper_bound(value)
:返回指向大于指定值的第一个元素的迭代器。 -
equal_range(value)
:返回一个范围,包含所有等于指定值的元素。对于set
,这个范围由lower_bound
和upper_bound
返回的迭代器界定。 -
begin()
:返回指向集合开始的迭代器。 -
end()
:返回指向集合结束(最后一个元素之后)的迭代器。 -
rbegin()
:返回指向集合逆向开始的迭代器。 -
rend()
:返回指向集合逆向结束的迭代器。 -
swap(set)
:交换当前集合的内容与另一个集合的内容。 -
key_comp()
:返回一个函数,该函数用于比较集合中的元素。 -
value_comp()
:返回一个函数,该函数用于比较集合中元素的值。
什么是map?
1,map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元 素。
2. 在map中,键值key通常用于排序和唯一地标识元素,而值value中存储与此键值key关联的 内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型 value_type绑定在一起,为其取别名称为pair。
3,在内部,map中的元素总是按照键值key进行比较排序的。
4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序 对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。
map的重点--[ ]
[ ]总的来说:
情况一:[ ]如果已经有元素,则是find的功能,或修改,返回元素的迭代器, key不存在时抛异常
情况二:[ ]如果没有元素,则执行insert的一个功能,即插入加修改,返回插入元素的迭代器, key不存在时抛异常
总结
1. map中的的元素是键值对
2. map中的key是唯一的,并且不能修改
3. 默认按照小于的方式对key进行比较
4. map中的元素如果用迭代器去遍历,可以得到一个有序的序列
5. map的底层为平衡搜索树(红黑树),查找效率比较高O(log_2 N)
6. 支持[]操作符,operator[]中实际进行插入查找
一个基础的实例:
map<string, string> high = { {"one","vector"}, {"two","List"} };
high.insert(make_pair("three", "queue"));
high["four"] = "stack";
for (const auto& e : high)
{
cout << e.first << " ," << e.second << endl;
}
map常用函数:
-
empty()
:检查map
是否为空。 -
size()
:返回map
中元素的数量。 -
clear()
:移除map
中的所有元素。 -
insert(value)
:向map
中插入一个新的键值对。如果键已存在,则不会插入,并且可能返回一个指向现有元素的迭代器。 -
erase(key)
:根据键删除元素。也可以删除指定范围内的元素或使用迭代器来删除元素。 -
find(key)
:查找具有指定键的元素。如果找到,返回指向该元素的迭代器;如果未找到,返回end()
迭代器。 -
count(key)
:返回map
中具有指定键的元素数量,对于map
来说总是0或1。 -
lower_bound(key)
:返回指向第一个不小于指定键的元素的迭代器。 -
upper_bound(key)
:返回指向第一个大于指定键的元素的迭代器。 -
equal_range(key)
:返回一个包含所有等于指定键的元素的区间,对于map
来说,这个区间由lower_bound
和upper_bound
返回的迭代器界定。 -
begin()
:返回指向map
开始的迭代器。 -
end()
:返回指向map
结束的迭代器。 -
rbegin()
:返回指向map
逆向开始的迭代器。 -
**
rend()``:返回指向
map`逆向结束的迭代器。 -
swap(map)
:交换当前map
的内容与另一个map
的内容。 -
key_comp()
:返回一个函数,该函数用于比较map
中的键。 -
value_comp()
:返回一个函数,该函数用于比较map
中的值(即键值对)。 -
get_allocator()
:返回一个副本,该副本是用于map
的分配器对象。 -
max_size()
:返回map
可以容纳的最大元素数量。 -
operator[](key)
:通过下标访问或设置与指定键关联的值。如果键不存在,它将插入一个新元素,并使用默认构造函数构造值。
引用习题:
一,二个数组的交集
给定两个数组 nums1
和 nums2
,返回 它们的 交集,输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序
解题代码:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> number1(nums1.begin(),nums1.end());
set<int> number2(nums2.begin(),nums2.end());
auto it1=number1.begin();
auto it2=number2.begin();
vector<int> answer;
while(it1!=number1.end()&it2!=number2.end())
{
if(*it1<*it2)
{
*it1++;
}
else if(*it1>*it2)
{
*it2++;
}
else
{
answer.push_back(*it1);
*it1++;
*it2++;
}
}
return answer;
}
};
二,前K个高频单词
给定一个单词列表 words
和一个整数 k
,返回前 k
个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
解题代码:
class Solution {
public:
// 仿函数
struct compare {
bool operator()(const pair<string, int>& h1,
const pair<string, int>& h2) {
return h1.second>h2.second;
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string, int> number;
for (const auto& e : words) {
number[e]++;
}
vector<pair<string, int>> temp(number.begin(), number.end());
stable_sort(temp.begin(), temp.end(), compare());
vector<string> answer;
for (int i = 0; i < k; i++) {
answer.push_back(temp[i].first);
}
return answer;
}
};