当前位置: 首页 > news >正文

【C++】priority_queue的使用及模拟实现(含仿函数介绍)

文章目录

  • 前言
  • 一、 priority_queue的介绍
  • 二、priority_queue的使用
  • 三、仿函数
  • 四、priority_queue的模拟实现


前言

一、 priority_queue的介绍(优先级队列是默认使用vector作为其底层存储数据的容器适配器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆)
二、priority_queue的使用 及 模拟实现
三、仿函数的介绍(通过重载函数调用运算符 operator() 使对象能够像函数一样被调用的编程方式)


一、 priority_queue的介绍

在这里插入图片描述

优先级队列是默认使用vector作为其底层存储数据的容器适配器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的地方,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。

priority_queue是堆结构,需要具备push_back()、pop_back()操作 并且 支持随机访问迭代器(堆排序需要支持随机访问)的线性结构,才可以作为priority_queue的底层容器,比如vector和deque都可以。默认情况下,如果没有为priority_queue实例化指定容器类,则使用标准容器vector(vector和deque的尾插尾删性能接近,但vector的随机访问效率优于deque)。

二、priority_queue的使用

函数声明接口说明
priority_queue( )构造一个空的优先级队列
template < class InputIterator > priority_queue (InputIterator first, InputIterator last)用迭代器区间构造优先级队列
empty( )检测优先级队列是否为空
size( )返回优先级队列中元素的个数
top( )返回优先级队列中最大(最小元素),即堆顶元素
push(x)在优先级队列中插入元素x
pop( )删除优先级队列中最大(最小元素),即堆顶元素

示例一(两种构造优先级队列的方式):

#include <queue>
#include <vector>
#include <iostream>
using namespace std;

int main()
{
	priority_queue<int> pri1; // 构造一个空的优先级队列
	pri1.push(5);
	pri1.push(6);
	pri1.push(9);
	pri1.push(4);
	pri1.push(2);
	while (!pri1.empty())
	{
		cout << pri1.top() << ' ';
		pri1.pop();
	}
	cout << endl;
    
	vector<int> vec{ 5,6,9,4,2 };
	priority_queue<int> pri2(vec.begin(),vec.end()); // 用迭代器区间构造优先级队列
	while (!pri2.empty())
	{
		cout << pri2.top() << ' ';
		pri2.pop();
	}
	cout << endl;
	return 0;
}

在这里插入图片描述
示例二(优先级队列默认是大堆,通过修改比较规则(显示传greater仿函数),可将优先队列变为小堆):

#include <queue>
#include <vector>
#include <iostream>
using namespace std;

int main()
{
	priority_queue<int, vector<int>, greater<int>> pri1;
	pri1.push(5);
	pri1.push(6);
	pri1.push(9);
	pri1.push(4);
	pri1.push(2);
	while (!pri1.empty())
	{
		cout << pri1.top() << ' ';
		pri1.pop();
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

三、仿函数

在C++中,仿函数是一种通过重载函数调用运算符 operator() 使对象能够像函数一样被调用的编程方式。

#include <iostream>
using namespace std;

namespace zh
{ 
    class Add
    {
    public:
        int operator()(int a, int b) {
            return a + b;
        }
    };

    class less
    {
    public:
        int operator()(int a, int b) {
            return a < b;
        }
    };

    class greater
    {
    public:
        int operator()(int a, int b) {
            return a > b;
        }
    };
}

int main()
{
    zh::Add add;
    zh::greater grt;
    zh::less ls;
    int a = 8;
    int b = 6;
    cout << add(8, 6) << endl; // add(8, 6) 等于 add.operator()(8,6)
    cout << grt(8, 6) << endl; // grt(8, 6) 等于 grt.operator()(8,6)
    cout << ls(8, 6) << endl; // ls(8, 6) 等于 ls.operator()(8,6)
    return 0;
}

在这里插入图片描述

四、priority_queue的模拟实现

#include <vector>
#include <assert.h>
using namespace std;

namespace zh
{
    template<class T>
    struct less // 模拟实现less类
    {
        bool operator()(const T& left, const T& right)
        {
            return left < right;
        }
    };

    template<class T>
    struct greater // 模拟实现greater类
    {
        bool operator()(const T& left, const T& right)
        {
            return left > right;
        }
    };

    template <class T, class Container = vector<T>,class Compare = less<T> >
    class priority_queue
    {
    private:
        void adjustup(int child) // 向上调整算法
        {
            int parent = (child - 1) / 2;
            while (child)
            {
                if (com(con[parent], con[child]))
                {
                    std::swap(con[child], con[parent]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                    break;
            }
        }
        void adjustdown(int parent) // 向下调整算法
        {
            int son = 2 * parent + 1;
            while (son < con.size())
            {
                if (son + 1 < con.size() && com(con[son], con[son + 1]))
                {
                    son += 1;
                }
                if (com(con[parent], con[son]))
                {
                    std::swap(con[parent], con[son]);
                    parent = son;
                    son = 2 * parent + 1;
                }
                else
                    break;
            }
        }
    public:
        priority_queue()
        { }

        template <class InputIterator>
        priority_queue(InputIterator first, InputIterator last)
            :con(first,last)
        {
            int cur = con.size() - 1;
            int root = (cur - 1) / 2;
            while (root >= 0)
            {
                adjustdown(root);
                root--;
            }
        }

        bool empty() const
        {
            return con.empty();
        }

        size_t size() const
        {
            return con.size();
        }

        const T& top() const
        {
            return con[0];
        }

        T& top() 
        {
            return con[0];
        }

        void push(const T& x)
        {
            con.push_back(x);
            adjustup(con.size() - 1);
        }

        void pop()
        {
            assert(con.size());
            std::swap(con[0], con[con.size() - 1]);
            con.pop_back();
            adjustdown(0);
        }

        void swap(priority_queue& ctr)
        {
            con.swap(ctr.con);
        }
    private:
        Container con;
        Compare com;
    };
}

相关文章:

  • v-form标签里的:rules有什么作用。如何定义。
  • Microsoft Edge浏览器的取证分析(基于Chromium)
  • CSGHub开源版本v1.5.0更新
  • Vulnhub靶场matrix-breakout-2-morpheus攻略
  • 在springboot3.x中使用Ehcache3.x
  • 网络编程之客户端通过服务器与另外一个客户端交流
  • oracle删除表中重复数据
  • 正则表达式与拓展正则简单理解
  • LeetCode[93] 复原 IP 地址
  • Mimikyu综合靶场训练
  • 大数据学习(74)-Hue元数据
  • Python标准库之os模块常用方法
  • Excel Script Lab学习笔记
  • Pytorch使用手册(专题五十)—自定义运算符
  • 《Python深度学习》第三讲:神经网络
  • sqlite mmap
  • nginx配置反向代理数据库等插件的原理和方式
  • Java线程6种状态的详细说明、状态转换关系(UML展示)
  • 汽车安全确认等级-中国等保
  • springboot基于session实现登录
  • 网站升级的内容包括哪些/全网关键词指数查询
  • 网站加入悬浮客服/seo优化有哪些
  • 小男孩做爰网站/企业seo排名
  • 成都单位网站设计/百度云登录首页
  • 沈阳科技网站建设/郑州网站建设外包
  • 内蒙古网站建设/网络销售推广平台