常函数的运用

统计一段词中出现次数最多的高频词(不区分大小写)

思路:用map存储每个词出现的频率(注意为什么不用unordered_map,因为若想实现“不区分大小写”的功能,就必须添加一个自定义比较器,unordered_map不支持这一选项),然后用priority_queue优先级队列的小顶堆特性找到高频词(TOPK问题转换为TOP1)。

(小顶堆求最大TOPK)堆(size = k)里存放的是当前元素的频率,其中堆顶的元素最小。加入新进来的元素,此时若size>k,弹出堆顶元素,调整堆。【大顶堆求最小TOPK类似】

在写自定义比较器的过程中出现bug

错误 C3848 具有类型“const my_less”的表达式会丢失一些 const-volatile 限定符以调用“bool my_less::operator ()(const std::string &,const std::string &)”

解决方案:仿函数后 + const 变成常函数。

原因:重载()(string)不具备const属性(即使添加const属性),应防止调用过程中改变string的值,所以将函数变成常函数。

参考https://blog.csdn.net/weixin_42157432/article/details/108573062

https://blog.csdn.net/qq_37613319/article/details/104360043(也有说Visual Studio的编译器优化的问题 —- 具有指定 const volatile 类型的变量智能调用相同或更大的const volatile限定的成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>
#include <queue>
#include <string>
#include <map>
#include <algorithm>
using namespace std;


class cmp {
public:
// 小顶堆(比较符号是>,greater) 大顶堆(比较符号是<,less)
bool operator()(pair<string, int> &a, pair<string, int> &b) {
//频率相同
if (a.second == b.second) {
//字符序小的优先
return a.first < b.first;
}
return a.second > b.second;
}
};

//自定义比较器:不区分字符串中的大小写
struct my_less {

struct nocase_compare {
//仿函数
bool operator ()( const char & c1, const char & c2) const {
return tolower(c1) < tolower(c2);
}
};
bool operator ()(const string &s1, const string &s2) const {
return lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), nocase_compare());
}

};


int main() {
string str = "高兴 开心 高兴 ++ -- .. aa aA bbb aec aa Aa AA AA ac aA beds bbb cc sss bbb cc";
//getline(cin, str);
map<string, int, my_less> count_map;

priority_queue<pair<string, int>, vector<pair<string, int>>, cmp>count_sort;

//cout << str.length() << endl;

int begin = 0;
for (int i = 0; i < str.size(); i++) {
if (str[i] == ' ' || i == str.length()-1) {
if (i == str.length() - 1) i++;
//substr(begin, num) 起始坐标与个数
string temp = str.substr(begin, i-begin);

//需要添加一个不区分大小写的比较器
if (count_map.find(temp) != count_map.end() )
count_map[temp]++;
else {
count_map.insert({ temp, 1});
}
begin = i+1;
}
}

cout << str << endl << endl;
cout << "频率统计:" << endl;
for (auto it : count_map) {
cout << it.first << " " << it.second << endl;
}
cout << endl;

int k = 1; // k = 3;
for (auto it = count_map.begin(); it != count_map.end(); it++) {
count_sort.push(*it);
if (count_sort.size() > k) {
count_sort.pop();
}
}
cout << "第" << k << "高频率统计:" << endl;
while (!count_sort.empty()) {
cout << count_sort.top().first << " " << count_sort.top().second << endl;
count_sort.pop();
}

return 0;
}

image-20210417180211561

将k改为任意数,则解决TOPK问题。

---------------- 本文结束 ----------------

本文标题:常函数的运用

文章作者:Pabebe

发布时间:2021年04月17日 - 17:03:52

最后更新:2021年04月17日 - 18:11:49

原始链接:https://pabebezz.github.io/article/e17bc1d7/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%