假设您决定使用std::unordered_map<std::string, int> 来获取项目的频率计数。这是一个好的开始,但需要解决的问题的另一部分是获得前 10 项。
每当一个问题询问“获取前 N 个”或“获取最小的 N”或类似问题时,都有各种获取此信息的方法。
一种方法是对数据进行排序并获取第一个N 项。使用std::sort 或良好的排序例程,该操作的时间复杂度应为O(N*log(N))。
另一种方法是使用N 项的最小堆或最大堆,具体取决于您要分别获得顶部N 还是底部N。
假设您有使用unordered_set 获取频率计数的工作代码。这是一个使用 STL 堆函数来获取顶部 N 项的例程。它尚未经过全面测试,但应该演示如何处理堆。
#include <vector>
#include <algorithm>
#include <iostream>
#include <unordered_map>
void print_top_n(const std::unordered_map<std::string, int>& theMap, size_t n)
{
// This is the heap
std::vector<std::pair<std::string, int>> vHeap;
// This lambda is the predicate to build and perform the heapify
auto heapfn =
[](std::pair<std::string, int>& p1, std::pair<std::string, int>& p2) -> bool
{ return p1.second > p2.second; };
// Go through each entry in the map
for (auto& m : theMap)
{
if (vHeap.size() < n)
{
// Add item to the heap, since we haven't reached n items yet
vHeap.push_back(m);
// if we have reached n items, now is the time to build the heap
if (vHeap.size() == n)
// make the min-heap of the N elements
std::make_heap(vHeap.begin(), vHeap.end(), heapfn);
continue;
}
else
// Heap has been built. Check if the next element is larger than the
// top of the heap
if (vHeap.front().second <= m.second)
{
// adjust the heap
// remove the front of the heap by placing it at the end of the vector
std::pop_heap(vHeap.begin(), vHeap.end(), heapfn);
// get rid of that item now
vHeap.pop_back();
// add the new item
vHeap.push_back(m);
// heapify
std::push_heap(vHeap.begin(), vHeap.end(), heapfn);
}
}
// sort the heap
std::sort_heap(vHeap.begin(), vHeap.end(), heapfn);
// Output the results
for (auto& v : vHeap)
std::cout << v.first << " " << v.second << "\n";
}
int main()
{
std::unordered_map<std::string, int> test = { {"abc", 10},
{ "123",5 },
{ "456",1 },
{ "xyz",15 },
{ "go",8 },
{ "text1",7 },
{ "text2",17 },
{ "text3",27 },
{ "text4",37 },
{ "text5",47 },
{ "text6",9 },
{ "text7",7 },
{ "text8", 22 },
{ "text9", 8 },
{ "text10", 2 } };
print_top_n(test, 10);
}
输出:
text5 47
text4 37
text3 27
text8 22
text2 17
xyz 15
abc 10
text6 9
text9 8
go 8
使用堆的好处是:
-
heapifying 的复杂性是O(log(N)),而不是排序例程提供的通常的O(N*log(N))。
-
请注意,只有当我们检测到最小堆上的顶部项目将被丢弃时,我们才需要进行堆化。
-
除了字符串到频率计数的原始映射之外,我们不需要存储频率计数到字符串的整个(多)映射。
-
堆将仅存储N元素,而不管原始映射中有多少项目。