目录
关联式容器
C++STL包含了序列式容器和关联式容器:
1.序列式容器里面存储的是元素本身,其底层为线性序列的数据结构。比如:vector,list,deque,forward_list(C++11)等。
2.关联式容器里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。比如:set、map、unordered_set、unordered_map等。
注意: C++STL当中的stack、queue和priority_queue属于容器适配器,它们默认使用的基础容器分别是deque、deque和vector。
树形结构与哈希结构
根据应用场景的不同,C++STL总共实现了两种不同结构的关联式容器:树型结构和哈希结构。
其中,树型结构容器中的元素是一个有序的序列,而哈希结构容器中的元素是一个无序的序列。
键值对
键值对是用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。
比如我们若是要建立一个英译汉的字典,那么该字典中的英文单词与其对应的中文含义就是一一对应的关系,即通过单词可以找到与其对应的中文含义。
在SGI-STL中关于键值对的定义如下:
template <class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2())
{}
pair(const T1& a, const T2& b) : first(a), second(b)
{}
};
在上面的pair类中:
是一个模板类,可以存放任意类型的键对值;
有两个成员变量:first和second;
一般使用first表示key,second表示value。 键值对要在类外进行访问,所以使用struct定义类而不用class。
make_pair
该函数用来创建pair类型的匿名对象。
根据上面pair类的定义,我们要想创建一个pair类型的匿名对象需要像下面这样写:
pair<string,int>("苹果",1);
上面的方式还需要指定参数类型,所以为了方便,就封装了一个函数模板make_pair,用来快速创建一个匿名对象:
make_pair("苹果",1);
make_pair函数模板的定义如下:
set
set的介绍
1.set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列(默认是升序);
2.set虽然是采用了键值对的方式存储数据,但是在set中,value就是key,即相当于是K模型,并且每个value必须是唯一的,不可以重复,所以可以使用set进行去重;
3.与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但在底层实际存放的是由<value, value>构成的键值对,因此在set容器中插入元素时,只需要插入value即可,不需要构造键值对;
4.set中的元素不能在容器中修改(元素总是const),因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。但是可以从容器中插入或删除它们;
5.在内部,set中的元素总是按照其内部比较对象所指示的特定严格弱排序准则进行排序。当不传入内部比较对象时,set中的元素默认按照小于来比较(默认是升序);
6.set容器通过key访问单个元素的速度通常比unordered_set容器慢,但set容器允许根据顺序对元素进行直接迭代;
7.set在底层是用平衡搜索树(红黑树)实现的,所以在set当中查找某个元素的时间复杂度为logN。
set模板参数列表
第一个模板参数T: set中存放元素的类型,实际在底层存储<value, value>的键值对;
Compare(仿函数):set中元素默认按照小于来比较(默认是升序);
Alloc:set中元素空间的管理方式,默认使用STL提供的空间配置器管理。
构造函数
构造函数有三个,分别是默认构造函数、使用迭代器区间的构造函数、拷贝构造函数。
下面用代码来使用上面三个构造函数:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
set<int> s1;//默认构造函数
vector<int> v = { 66,5,4,11,66,66,77,8,9,22,10,99 };
set<int> s2(v.begin(), v.end());//迭代器区间构造
set<int> s3(s2);//拷贝构造
//打印s1
for (auto& e : s1)
{
cout << e << " ";
}
cout << endl;
//s1内容为空
//打印s2
for (auto& e : s2)
{
cout << e << " ";
}
cout << endl;
//s2打印出来为4 5 8 9 10 11 22 66 77 99
//打印s3
for (auto& e : s3)
{
cout << e << " ";
}
cout << endl;
//s3打印出来为4 5 8 9 10 11 22 66 77 99
}
根据结果我们可以看到set具有排序的功能(默认是升序),而且在数组中相同的元素经放在set容器之后就没有相同的元素了,说明了set具有去重的功能。set具有去重的功能,其底层是二叉搜索树,不能存放相同的元素。
迭代器
set的输出结果是升序的,其底层是二叉搜索树,打印二叉搜索树时使用中序打印出来的就是升序,所以set的迭代器在++时,移动的顺序就是中序遍历的顺序,所以使用迭代器遍历时得到的结果和二叉搜索树中序遍历得到的结果一致。
set迭代器的使用和之前学过的容器一样:
代码示范:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> v = { 66,5,4,11,66,66,77,8,9,22,10,99 };
set<int> s1(v.begin(), v.end());//迭代器区间构造
//正向迭代器的使用
set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//反向迭代器的使用
set<int>::reverse_iterator rit = s1.rbegin();
while (rit != s1.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}
插入(insert)
1.插入一个指定值并且返回一个键值对,返回的键值对中迭代器指向新插入的位置。
返回的是pair类型的对象,其中pair的第一个成员是迭代器,其指向的是插入的元素在set中的位置;第二个成员是bool类型,如果成功插入pair类中的第二个成员为true,插入失败pair类中的第二个成员为false。所以这里insert能够做到两个功能:查找和插入(查找成功返回false,查找失败返回true)。
pair<iterator,bool> insert (const value_type& val);
2.在指定的位置插入数据,并且返回插入的位置:
iterator insert (iterator position, const value_type& val);
3.将一段迭代器区间插入到set对象中:
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
代码示范:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> v = { 66,5,4,11,66,66,77,8,9,22,10,99 };
set<int> s1(v.begin(), v.end());//迭代器区间构造
//正向迭代器的使用
set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//构造一个pair类型的对象
pair<set<int>::iterator, bool> p;
//接收插入之后的返回值
p = s1.insert(67);
it = s1.begin();
//打印插入的值和是否成功
cout << *(p.first) << ":" << p.second << endl;
//打印结果:67:1 打印成功
p = s1.insert(67);
//打印插入的值和是否成功
cout << *(p.first) << ":" << p.second << endl;
//打印结果:67:0 打印失败
}
指定位置插入有可能会破环二叉搜索树的结构,所以不建议使用指定位置插入。
删除(erase)
1.删除指定迭代器位置的值:
void erase (iterator position);
2.删除指定值并且返回删除指定值的个数(在set容器中没有重复值所以返回值为1,在multiset中才能体现出来):
size_type erase (const value_type& val);
3.删除迭代器区间中所有的值(迭代器区间是set的迭代器区间):
void erase (iterator first, iterator last);
在set中删除一个数据,并且保持结构不变。
查找(find)
iterator find (const value_type& val) const;
查找set中某个元素,如果存在返回所在位置的迭代器,如果不存在,就返回迭代器end()。
代码示范:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> v = { 66,5,4,11,66,66,77,8,9,22,10,99 };
set<int> s1(v.begin(), v.end());//迭代器区间构造
//正向迭代器的使用
set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
set<int>::iterator it1 = s1.find(66);//存在返回所在值的迭代器位置
set<int>::iterator it2 = s1.find(666);//不存在返回end()
if (it1 != s1.end())
cout << "该值存在" << ":" << *(it1) << endl;
else
cout << "该值不存在" << endl;
}
count函数
size_type count (const value_type& val) const;
和find功能类似,返回指定数据的个数,如果不存在则返回0。
但是由于set具有去重的功能,所以这里的返回值要么是1,要么是0,在set容器中可以用来查找数据是否存在。
获取上下边界
获取下边界(以传入的值为下限,返回一个迭代器):
iterator lower_bound (const value_type& val) const;
获取上边界(以传入的值为上限,返回一个迭代器):
iterator upper_bound (const value_type& val) const;
代码示范:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> v = { 66,5,4,11,66,66,77,8,9,22,10,99 };
set<int> s1(v.begin(), v.end());//迭代器区间构造
//正向迭代器的使用
set<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//输出4 5 8 9 10 11 22 66 77 99
set<int>::iterator it1 = s1.lower_bound(11);//获取11所在位置的迭代器
set<int>::iterator it2 = s1.upper_bound(66);//获取66下一个数据的迭代器
s1.erase(it1, it2);//删除是左闭右开的,获取66下一个位置的迭代器才能将66也删除
it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//输出4 5 8 9 10 77 99
}
其他相关操作
成员函数 | 功能 |
---|---|
swap | 交换两个set对象 |
clear | 清除set对象中所有数据,但是不删除set对象 |
empty() | 判断set是否为空,如果为空返回true,否则返回flase |
size() | 返回容器的数据个数,类型为size_t(unsigned int) |
max_size() | 返回容器中最多能够存放的数据个数 |
multiset
multiset和set几乎一致,在同一个头文件中,set的功能是排序和去重,而multiset容器仅仅完成排序,容器中允许有相同的数据存在(区别在于multiset支持数据重复,而set不可以)。
在set容器中count函数和erase函数中第二个重载函数(返回被删除个数)没有实际作用,但在multiset中就能够体现它们的作用:
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> v = { 66,5,4,11,66,66,9,22,10,4};
multiset<int> s1(v.begin(), v.end());//迭代器区间构造
//正向迭代器的使用
multiset<int>::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//输出4 4 5 9 10 11 22 66 66 66
int num1 = s1.count(66);//统计元素66的数据个数
cout << num1 << endl;//输出3
int num2 = s1.erase(66);//删除元素66并且返回删除个数
cout << num2<< endl;//输出3
it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
在查找函数find中返回的迭代器位置是查找到的第一个数据的迭代器位置。
map
map是一个关联式容器,底层是二叉搜索树。
map中存放的是键值对,有两个模板参数Key和T,组成键值对。
map的介绍
1.map是关联式容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素;
2.在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair:typedef pair<const key, T> value_type;
3.在内部,map中的元素总是按照键值key进行比较排序的;
4.map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列);
5.map支持下标访问符,即在[]中放入key,就可以找到与key对应的value;
6.map的底层结构为平衡二叉搜索树(红黑树)。
构造函数
默认构造函数创建的map对象为空
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
插入时可以使用pair创建对象,也可以使用make_pair创建匿名对象:
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string, int> fruit;
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
//插入时可以使用pair创建对象,也可以使用make_pair创建匿名对象
pair<string, int> p("苹果", 1);
fruit.insert(p);
fruit.insert(make_pair("香蕉", 1));
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
return 0;
}
也可以使用迭代器区间进行构造:
template <class InputIterator>
map (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
代码示范:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
vector<pair<string, int>> v = { {"香蕉",2},{"苹果",3}, {"梨",2}, {"西瓜",6} };
map<string, int> fruit(v.begin(),v.end());//使用vector迭代器区间进行构造
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
//进行拷贝构造
//auto f(fruit);//可以使用自动推导类型
map<string, int> f(fruit);
for (auto& e : f)
{
cout << e.first << ":" << e.second << endl;
}
}
注意:
map具有去重的功能,不能插入相同的键值对(不支持重复的数据),同时不能插入key值相同value值不同的键值对。
map的判断逻辑都是只看key值,即first所表示的变量。
插入(insert)
map的插入函数和set的一样,只是map中插入的是键值对。
第一个函数中返回的是一个键值对,返回的键值对pair<iterator,bool>,first是插入键值对所在位置的迭代器,second是bool值,如果插入成功bool值为true,插入失败bool值为false。
迭代器区间插入时,如果map中已经存在key值就不再进行插入。
代码示范:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
map<string, int> fruit;//使用默认构造函数
pair<map<string, int>::iterator, int> ret = fruit.insert(make_pair("黄瓜", 6));//插入一个键值对,返回键值对
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
vector<pair<string, int>> v = { {"香蕉",2},{"苹果",3}, {"梨",2}, {"西瓜",6} };
fruit.insert(v.begin(), v.end());//插入迭代器区间的数据
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
}
除了像插入这种增加操作,需要一个键值对,其他操作都是根据键值对中的键值key来处理的。
查找(find)
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
根据指定要查找键值对中的键值key去查找,find函数根据key去查找是否存在的。
如果存在,找到以后返回键值对所在位置的迭代器,没有找到返回end迭代器。
代码示范:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
map<string, int> fruit;
vector<pair<string, int>> v = { {"香蕉",2},{"苹果",3}, {"梨",2}, {"西瓜",6} };
fruit.insert(v.begin(), v.end());
for (auto& e : fruit)
{
cout << e.first << ":" << e.second << endl;
}
cout << endl;
map<string,int>::iterator ret = fruit.find("香蕉");
if (ret != fruit.end())
cout << (*ret).first << ":" << (*ret).second << endl;
//cout << ret->first << ":" << ret->second << endl;
else
cout << "找不到" << endl;
}
在上面的代码中cout << (*ret).first << “:” << (*ret).second << endl;输出的时候我们可以先对迭代器解引用再调用first和second,但是平时使用更多的还是->即cout << ret->first << “:” << ret->second << endl;这种方式,这里应该有两个->但是这里省略了一个。
map和set一样,不支持修改,因为可能会破坏二叉搜索树的结构。
operator[]
我们可以使用map统计字符数组中水果出现的次数:
#include <iostream>
//#include <set>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& e : arr)
{
//通过查找函数,找到返回所在位置的迭代器,没找到返回end迭代器
map<string, int>::iterator it = countMap.find(e);
if (it == countMap.end())
{
//等于end迭代器时,插入
countMap.insert(make_pair(e, 1));
}
else
{
//不等于时second++
it->second++;
}
}
for (auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
}
但是在map中也可以使用[],返回的是第二个模板参数,所以上面的代码可以这样写:
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main()
{
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
"苹果", "香蕉", "苹果", "香蕉" };
map<string, int> countMap;
for (auto& e : arr)
{
countMap[e]++;
}
for (auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
}
operator[]在库中的声明:
可以看到函数参数是键值对中的key值,也就是说key值充当下标。
调用此函数相当于调用:
(*((this->insert(make_pair(k,mapped_type()))).first)).second
总结来说三个步骤:
1.调用insert函数插入键值对;
2.获取insert函数插入成功之后返回的键值对中的first迭代器参数;
3.拿到该迭代器位置键值对中的second,并返回。
对应分解代码如下:
mapped_type& operator[](const key_type& k)
{
//1、调用insert函数插入键值对
pair<map<k,mappd_typed()>::iterator, bool> ret = insert(make_pair(k, mapped_type()));
//2、获取insert函数插入成功之后返回的键值对中的first迭代器参数;
map<k,mappd_typed()>::iterator it = ret.first;
//3、拿到该迭代器位置键值对中的second,并返回
return (*it).second;
//return it->second;
}
也可以这样理解:
V& operator[](const K& key)
{
//1、查找 2、插入
pair<map<k,V()>::iterator, bool> ret = insert(make_pair(key, V());
//3、修改
return ret.first->second;
}
那么countMap[e]++;是如何实现插入、查找、修改的呢?
首先插入e,map中如果不存在e,则boo设置为true,成功插入,此时返回的是插入位置second的引用,引用为0,++之后变成1;如果map中已经存在e,bool值为false,直接返回e位置键值对的second的引用,并且++。
其他相关操作
函数 | 函数说明 |
---|---|
begin和end | 获取容器中第一个元素的迭代器和最后一个元素下一个位置的迭代器 |
rbegin和rend | 获取容器中最后一个元素的迭代器和第一个元素前一个位置的迭代器 |
size | 获取容器中元素的个数 |
empty | 判断容器是否为空 |
clear | 清空容器 |
swap | 交换两个容器中的数据 |
count | 获取容器中指定key值的元素个数 |
multimap
multimap和map都在头文件map中,multimap的使用和map一样(multimap支持相同数据,而map不支持)。
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main()
{
vector<pair<string, int>> v = { {"西瓜",1},{"香蕉" ,2},{"西瓜",2},{"芒果",3} };
multimap<string, int> countMap;
for (auto& e : v)
{
countMap.insert(e);
}
for (auto& e : countMap)
{
cout << e.first << ":" << e.second << endl;
}
}
但是要注意的是multimap中没有重载[],因为multimap中允许有多个重复键值对,如果重载的话不知道返回哪个。
multimap的inser函数中,没有返回键值对的,返回的是键值对插入之后所在位置的迭代器。
map和set在OJ中的使用
1.随机链表的复制
随机链表的复制
思路:
可以使用map容器让源节点和拷贝结点之间建立kv关系,可以根据map中的kv关系找到random指针指向。
class Solution {
public:
Node* copyRandomList(Node* head) {
map<Node*,Node*> copyNodeMap;
Node* cur = head;
Node* copyhead = nullptr;
Node* copytail = nullptr;
//先将链表中的结点都拷贝
while(cur)
{
//创建新结点
Node* copy = new Node(cur->val);
//源节点和拷贝结点建立链接关系
//K V
copyNodeMap[cur] = copy;
if(copytail == nullptr)
{
copyhead = copytail = copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
cur = cur->next;
}
cur = head;
Node* copy = copyhead;
while(cur)
{
if(cur->random == nullptr)
copy->random = nullptr;
else
{
//根据链接关系找到random指针指向
copy->random = copyNodeMap[cur->random];
}
cur = cur->next;
copy = copy->next;
}
return copyhead;
}
};
2.环形链表
环形链表
思路:
用insert把数据存到set容器中,若存在环,insert时出现插入相同的数,second会返回false
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
set<ListNode*> s;
ListNode* cur = head;
while(cur)
{
auto ret = s.insert(cur);
if(ret.second == false)
return cur;
cur = cur->next;
}
return nullptr;
}
};
3.两个数组的交集
两个数组的交集
思路:用set存储数据,排序去重后,用两个指针往后走,相等的就是交集
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//去重+排序
// set<int> s1;
// set<int> s2;
// for(auto& e : nums1)
// {
// s1.insert(e);
// }
// for(auto& e : nums2)
// {
// s2.insert(e);
// }
//也可以直接使用迭代器区间构造
set<int> s1(nums1.begin(),nums1.end());
set<int> s2(nums2.begin(),nums2.end());
//set<int>::iterator it1 = s1.begin();
//set<int>::iterator it2 = s2.begin();
auto it1 = s1.begin();
auto it2 = s2.begin();
vector<int> v;
//在s1里面找s2里的数据
while(it1 != s1.end() && it2 != s2.end())
{
if(*it1 == *it2)
{
v.push_back(*it1);
++it1;
++it2;
}
else if(*it1 < *it2)
{
it1++;
}
else{
it2++;
}
}
return v;
}
};
4.前K个高频单词
前K个高频单词
思路1:
可以先使用map将words中的单词统计出现次数,
然后将其放入vector数组中,对vector数组进行排序,
(sort是不稳定的排序算法,可以使用库中提供的稳定的排序算法stable_sort)因为stable_sort/sort函数默认是升序,
所以可以实现一个仿函数用来由高到低排序(要注意在实现仿函数时,参数是pair类型,注意是first参数的比较还是second参数的比较);最后将排完序之后的vector中前k个键值对中的first参数(字符)尾插到要返回的vector中。
map不能直接使用sort,因为sort底层是一个随机迭代器,而map底层是一个双向迭代器,所以可以先将数据放到vector中再排序。
代码实现:
class Solution {
public:
//仿函数
struct Greater{
bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
{
//出现次数大的排前面,当出现次数相同时字母小的排前面
return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first);
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string,int> countwords;
//统计单词出现次数
for(auto& e : words)
{
countwords[e]++;
}
//放入vector数组中
vector<pair<string,int>> v1(countwords.begin(),countwords.end());
//排序,放入仿函数
stable_sort(v1.begin(),v1.end(),Greater());
//sort(v1.begin(),v1.end(),Greater());
vector<string> v2;
//将符合条件(前k个单词)的放入vector数组中
for(int i = 0; i < k; i++)
{
v2.push_back(v1[i].first);
}
return v2;
}
};
思路2:
上面的思路我们使用的是sort进行排序,虽然map本身就能排序,但是因为map的本质是排序加去重,所以不能使用,但是可以使用multimap,这里要注意当两个键值相同的时候要如何保证value的顺序,可以通过仿函数来控制。
代码实现:
class Solution {
public:
//仿函数
struct Greater{
bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2) const
{
//出现次数大的排前面,当出现次数相同时字母小的排前面
return kv1.second > kv2.second || (kv1.second == kv2.second && kv1.first < kv2.first);
}
};
vector<string> topKFrequent(vector<string>& words, int k) {
map<string,int> countwords;
//统计单词出现次数
for(auto& e : words)
{
countwords[e]++;
}
//这里使用multiset,这里使用仿函数比较
multiset<pair<string,int>,Greater> sortset(countwords.begin(),countwords.end());
vector<string> v2;
//放入vector数组中
multiset<pair<string,int>,Greater>::iterator it = sortset.begin();
//auto it = sortset.begin();
while(k--)
{
v2.push_back(it->first);
++it;
}
return v2;
}
};
注意这里的仿函数后面要加上const(避免权限放大问题),不然multiset<pair<string,int>,Greater> sortset(countwords.begin(),countwords.end());这里会报错。