C++基础(三)——STL优先级队列

这篇具有很好参考价值的文章主要介绍了C++基础(三)——STL优先级队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、定义

priority_queue模板

模板输入
1、元素类型
2、容器类型
3、函数对象类型

priority_queue<元素类型, 容器类型, 函数对象类型> qqq;

大顶堆

priority_queue<int> name;
priority_queue默认为大顶堆
故定义也可以写作:
priority_queue<int, vector<int>, less<int> > ay;

小顶堆

如果需要构建一个小顶堆,可以改变定义方式为:
priority_queue<int, vector<int>, greater<int> > ay;
使用std::greater模板无需自定义比较函数。

自定义比较函数:

#include <queue>

struct Compare {
    bool operator()(int a, int b) {
        return a > b; 
    }
};

int main() {
    std::priority_queue<int, std::vector<int>, Compare> pq; // 使用自定义的比较函数
    pq.push(3);
    pq.push(1);
    pq.push(2);

    while (!pq.empty()) {
        std::cout << pq.top() << " ";
        pq.pop();
    }

    return 0;
}

二、接口

优先级队列只能通过top()访问队首元素(优先级最高的那个元素)
pop():弹出优先级最高的元素
push():塞元素进队列
empty() size():是否空和元素个数

#include <iostream>
#include <queue>
using namespace std;
int main() {
    priority_queue<int> ay;
    ay.push(3);
    ay.push(6);
    ay.push(2);
    cout << ay.top() << endl;   // result: 6
    ay.pop();   // 弹出6,剩3、2
    return 0;
}

三、例子

题目:找出topK的元素

建立 [元素, 元素出现个数] 的键值对
优先级队列中的数据结构为pair<int,int>
将优先级队列的优先级设置为值的小顶堆

定义:
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
仿函数mycomparison如下:

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

总体:

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;
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }

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

        // 用固定大小为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();
            }
        }

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

    }
};

方法二:
自定义sort函数排序规则文章来源地址https://www.toymoban.com/news/detail-492045.html

class Solution {
public:
    static bool compareByValue(const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
        return lhs.second > rhs.second;
    }

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

        // 将键值对存储到 vector 中
        vector<pair<int, int>> vec(mymap.begin(), mymap.end());

        // 使用自定义的比较器函数进行排序
        std::sort(vec.begin(), vec.end(), Solution::compareByValue);
        // 按照无序容器 unordered_map 中的值来排序

        // 遍历输出排序后的键值对
        for (int i = 0; i < k; ++i)  res.push_back(vec[i].first);
        
        return res;
    }
};

四、实现一个优先级队列

#include<iostream>
#include<functional>
#include<string.h>//memecpy
#include<time.h>    // time
using namespace std;


//优先级队列实现

class PriorityQueue {
public:
    using Comp = function<bool(int, int)>;
    PriorityQueue(int cap = 20, Comp comp = greater<int>())
        : size_(0)
        , cap_(cap)
        , comp_(comp) {
        que_ = new int[cap_];
    }

    PriorityQueue(Comp comp) 
        : size_(0), cap_(20), comp_(comp) {
        que_ = new int [cap_];
    }

    ~PriorityQueue() {
        delete[] que_;
        que_ = nullptr;
    }

public:
    //入堆操作
    void push(int val) {
        //判断扩容
        if (size_ == cap_) {
            int* p = new int[2 * cap_];
            memcpy(p, que_, cap_ * sizeof(int));
            delete[]que_;
            que_ = p;
            cap_ *= 2;
        }

        if (size_ == 0) {
            //只有一个元素不用进行堆的上浮调整
            que_[size_] = val;
        } else {
            // 堆里面有多个元素,需要进行上浮调整
            siftUp(size_, val);
        }
        size_++;
    }

    void pop() {
        if (size_ == 0) {
            throw "container is empty";
        }
        size_--;
        if (size_ > 0) {
            //删除堆顶元素, 还有剩余的元素, 要进行堆的下沉调整
            siftDown(0, que_[size_]);
        }
    }

    bool empty() const {
        return size_ == 0;
    }

    int top() const {
        if (size_ == 0) {
            throw "container is empty!"; 
        }
        return que_[0];
    }

    int size() const {
        return size_;
    }

private:
    //入堆上浮调整 O(log n)
    void siftUp(int i, int val) {
        while (i > 0) {   //最多计算到根节点 0号位
            int father = (i - 1) / 2;
            if (comp_(val, que_[father])) {  // 默认大于 当前元素比父节点的值大
                que_[i] = que_[father];
                i = father;
            } else {
                break;
            }
        }

        // 把val放到i的位置
        que_[i] = val;
    }

    //出堆下沉调整  当前节点与孩子节点比较
    void siftDown(int i, int val) {
        //i下沉不能超过最后一个有孩子的节点 (size_ - 1 - 1) / 2
        while (i <= (size_ - 1 - 1) / 2) {
            int child = 2 * i + 1; // 第i个节点的左孩子
            if (child + 1 < size_) {  // 有右孩子
                if (child + 1 < size_ && comp_(que_[child + 1], que_[child])) {
                    // 如果i节点右孩子大于左孩子, child 记录 右孩子的值
                    child = child + 1;
                }
            }

            if (comp_(que_[child], val)) {
                que_[i] = que_[child];
                i = child;
            } else {
                break;  //已经满足堆的性质 提前结束
            }
        }
        que_[i] = val;
    }
private:
    int* que_;  //指向动态扩容的数组
    int size_;  // 数组元素的个数
    int cap_; //数组的总空间大小
    Comp comp_; //比较器对象
};
int main() {
//    PriorityQueue que;  //基于大根堆实现的优先级队列
    PriorityQueue que([](int a, int b) {return a < b;}); // 小根堆
    srand(time(NULL));

    for (int i = 0; i < 10; i++) {
        que.push(rand() % 100);
    }
  
    while (!que.empty()) {
        cout << que.top() << " ";
        que.pop();
    }

    cout << endl;

    return 0;
}

到了这里,关于C++基础(三)——STL优先级队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++基础(三)——STL优先级队列

    模板输入 1、元素类型 2、容器类型 3、函数对象类型 priority_queueint name; priority_queue默认为大顶堆 故定义也可以写作: priority_queueint, vectorint, lessint ay; 如果需要构建一个小顶堆,可以改变定义方式为: priority_queueint, vectorint, greaterint ay; 使用std::greater模板无需自定义比较函数。

    2024年02月09日
    浏览(42)
  • 【STL】priority_queue(优先级队列)详解及仿函数使用(附完整源码)

    1. priority_queue介绍和使用 1.1 priority_queue介绍 优先级队列也是在 queue 里: 因此和 queue 一样, priority_queue 也是一个容器适配器。priority_queue官方文档 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。 类似于堆,在堆中可以随

    2024年02月08日
    浏览(31)
  • 【C++初阶】模拟实现优先级队列priority_queue

    👦个人主页:@Weraphael ✍🏻作者简介:目前学习C++和算法 ✈️专栏:C++航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨ 优先级队列顾名思义就是 按优先级出队列 priority_queue 是一个容器适配器,默认使用

    2024年02月10日
    浏览(29)
  • 【C++】详解priority_queue(优先级队列)与函数对象

    目录 一、priority_queue 的介绍和使用 1.1priority_queue 的介绍 2.2priority_queue 的使用 二、仿函数 2.1什么是仿函数 2.2仿函数的作用 三、函数对象的特点(知识点多) 3.1分析特点5(比较普通函数与函数对象) 3.1.1利用普通函数传递参数 拓展之:深度剖析函数利用模板的本质 3.1.2利用

    2024年02月08日
    浏览(29)
  • C++——优先级队列(priority_queue)的使用及实现

    目录 一.priority_queue的使用 1.1、基本介绍 1.2、优先级队列的定义 1.3、基本操作(常见接口的使用) 1.4、重写仿函数支持自定义数据类型 二.priority_queue的模拟实现 2.1、构造重要的调整算法 2.2、常见接口的实现 push() pop() top() empty()、size()  三.利用仿函数改进调整算法 我们之前

    2024年02月02日
    浏览(29)
  • C++ STL学习之【优先级队列】

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2019 版本 16.11.17 优先级队列 priority_queue 是容器适配器中的一种,常用来进行对数据进行优先级处理,比如优先级高的值在前面,这其实就是初阶数据结构中的 堆 ,它俩本质上是一样东西,底层都是以数

    2024年02月05日
    浏览(35)
  • 【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 和C语言学习期间的学习顺序一样 顺序表,链表过了就是栈和队列 但是栈和队列非常特殊,它的内部结构 并不是靠自己实现的,而是一种 适配

    2024年02月08日
    浏览(32)
  • 【C++初阶10-stack&queue】STL中的栈和队列(附优先级队列

    本期分享:STL中的栈和队列。 在数据结构初阶时,我们已经学习这来那个两种数据结构,如今来看STL中的,不过是更加标准化。而实现起来,会简单得超乎你想象! 文中不足错漏之处望请斧正! STL中的栈和队列是容器适配器。容器适配器是对某种已有容器的再次封装。 比如

    2024年02月06日
    浏览(33)
  • 优先级队列priority_queue

    关于less建大根堆,输出降序序列,greater建小根堆,输出升序序列,这点和sort()函数相反,参考我的这篇博客 底层原理 priority_queue底层维护着一个对应类型的,vector物理结构,但相当于堆排序的结构,这个vector逻辑结构是一个二叉堆; 每次 插入数据 ,我们插在堆尾(vector尾),

    2024年02月16日
    浏览(30)
  • 优先级队列priority_queue模拟实现

    🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏:【C++的学习】 📝📝本篇内容:C++容器优先级队列priority_queue模拟实现 ⬆⬆⬆⬆上一篇:string模拟实现 💖💖作者简介:轩情吖,请多多指教( •̀֊•́ ) ̖́- ①优先级队列是一种容器适配器,它的第一个元素总是

    2024年02月02日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包