关于堆的碎碎念

构建最大最小堆的方法

最小堆
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;

std::priority_queue<T, Container, Compare>:这是std::priority_queue的模板定义。

  • T:元素的类型(在这个例子中是int)。
  • Container:底层容器类型,它用于存储队列中的元素(在这个例子中是std::vector<int>)。
  • Compare:比较对象,它用于定义堆的顺序(在这个例子中是std::less<int>

通过指定第三个参数为std::greater<int>,可以创建一个使用"大于"关系进行比较的最小堆。

在这种情况下,std::priority_queue的默认比较操作符std::less<int>会被替换为std::greater<int>,这意味着在插入和弹出元素时,较大的元素将具有更低的优先级,从而形成了一个最小堆。

在C++中的priority_queue默认情况下是一个最大堆,这意味着队列的顶部是最高优先级的元素。在使用默认的比较方式(比如对于整数,就是使用std::less<int>)时,最大的元素具有最高的优先级,因此会位于队列的顶部。

当我们自定义一个比较类或函数时,我们实际上是在告诉priority_queue如何确定两个元素之间的优先级。如果比较操作返回true,那么priority_queue会假定左侧参数具有更低的优先级。

所以,让我们看看这个自定义的比较类mycomparison

class mycomparison {
public:
    bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
        return lhs.second > rhs.second;
    }
};

这个比较操作实际上说的是:当 lhs.second rhs.second 时,我们认为 lhs具有更低的优先级(就像返回true意味着"这个元素应该排在另外一个元素后面")。因为我们希望priority_queue是一个最小堆,所以我们希望拥有最小second值的元素在队列的顶部

这就是为什么当创建了如下的priority_queue

priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;

unordered_map<int, int>::iterator是一个迭代器类型,用于遍历和访问unordered_map(无序映射)容器中的元素。

it是一个迭代器对象,通过map.begin()函数获取的是指向unordered_map容器中第一个键值对的迭代器,即指向容器的起始位置。

在C++中,迭代器类似于指针,可以通过解引用操作符*来获取迭代器指向的元素。在这个例子中,*it表示迭代器it指向的键值对。

迭代器的使用可以方便地遍历容器中的元素。在这段代码中,通过迭代器it遍历了整个map,从开始位置到结束位置(map.begin()map.end()),并对每个键值对进行了相应的操作。

// 用固定大小为k的小顶堆,扫面所有频率的数值
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
    pri_que.push(*it);
    if (pri_que.size() > k) { // 如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
        pri_que.pop();
    }
}


// 注意:我们需要创建一个新的pair来避免const问题  
for (const auto &entry : map) { // 使用基于范围的for循环更简洁  
     que.push({entry.first, entry.second}); // 创建一个新的pair并推入队列  
     if (que.size() > k) {  
         que.pop();  
     }  
} 

347. 前 K 个高频元素

#include <iostream>
#include <queue>
#include <unordered_map>
#include <utility>

using namespace std;

class Solution
{
public:
   // 小顶堆
   class mycomparison
   {
   public:
      bool operator()(const pair<int, int> &lhs, const pair<int, int> &rhs)
      {
         return lhs.second > rhs.second;
      }
   };

   vector<int> topKFrequent(vector<int> &nums, int k)
   {
      // 统计元素出现频率
      unordered_map<int, int> map; // map<nums[i],对应出现的次数>
      for (int i = 0; i < nums.size(); i++)
      {
         map[nums[i]]++;
      }

      priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;

      for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++)
      {
         pri_que.push(*it);
         if (pri_que.size() > k)
         {
            pri_que.pop();
         }
      }

      vector<int> result(k);
      for (int i = k - 1; i >= 0; i--)
      {
         result[i] = pri_que.top().first;
         pri_que.pop();
      }
      return result;
   }
};

int main()
{
   Solution solution;
   vector<int> nums = {1, 1, 1, 2, 2, 3};
   int k = 2;

   vector<int> result = solution.topKFrequent(nums, k);

   // 输出结果
   cout << "Top " << k << " frequent elements are: ";
   for (int num : result)
   {
      cout << num << " ";
   }
   cout << endl;

   return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值