C++模拟实现priority_queue(优先级队列)

一、priority_queue的函数接口

从上图我们可以看出, priority_queue也是一个容器适配器,我们使用vector容器来模拟实现priority_queue。

namespace bit

{

  #include<vector>

  #include<functional>

  template <class T, class Container = vector<T>, class Compare = less<T> >

  class priority_queue

  {

  public:

    priority_queue();

    template <class InputIterator>

    priority_queue(InputIterator first, InputIterator last);

    bool empty() const;

    size_t size() const;

    T& top() const;

    void push(const T& x);

    void pop();

  private:

    Container c;

    Compare comp;

  };

};

我们主要实现的接口便是push、pop、top、size、empty。

在这里为什么要使用vector来模拟实现priority_queue呢,因为实现priority_queue就和我们实现堆一样,我们要实现对找到父亲和孩子节点,就必须要使用数组进行查找,所以实现priority_queue的底层是vector。

对于堆的知识可以移步:

二叉树详解_二叉树原理详解-CSDN博客

二、 模拟实现priority_queue

2.1 greater和less

template<class T>
struct less
{
    bool operator()(const T& x, const T& y)
    {
        return x < y;
    }
};

template<class T>
struct greater
{
    bool operator()(const T& x, const T& y)
    {
        return x > y;
    }
};

我们实现greater和less就是为了实现建大堆和建小堆,我们只能够通过修改代码父子的大于小于关系才能修改建大堆还是小堆,我们实现greater和less便可以通过模板来控制建大堆还是建小堆了。

2.2 向上调整和向下调整

void Adjustdown(size_t parent)
{
    size_t child = parent * 2 + 1;
    if (child + 1 < c.size() && comp(c[child], c[child + 1]))
    {
        child++;
    }
    while (child < c.size())
    {
        if (comp(c[parent], c[child]))
        {
            swap(c[parent], c[child]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

void Adjustup(size_t child)
{
    size_t parent = (child - 1) / 2;
    while (child > 0)
    {
        if (comp(c[parent], c[child]))
        {
            swap(c[parent], c[child]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

向上调整和想要调整主要是为了插入和删除后使新的数组能够重新调整为大堆或小堆,这里不再详讲,不了解的可以看:二叉树详解_二叉树原理详解-CSDN博客.

2.3 模拟实现priority_queue的构造函数

priority_queue()
{
}


template <class InputIterator>

priority_queue(InputIterator first, InputIterator last)
{
    while (first != last)
    {
        c.push_back(*first);
        ++first;
    }
    for (size_t i = c.size() - 1 - 1; i >= 0; i--)
    {
        Adjustdown(i);
    }
}

第一个无参的构造函数可以不写,因为会自动调用vector自己的构造, 而另外一个使用迭代器区间进行构造的,我们只需将每一个数据进行尾插,然后进行调整建堆即可。

2.4 模拟实现priority_queue的push

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

 push就是将数据尾插,然后从最后一个数据开始进行向上调整,使其重新为堆。

2.5 模拟实现priority_queue的pop

void pop()
{
    swap(c[0], c[c.size() - 1]);
    c.pop_back();
    Adjustdown(0);
}

对堆进行删除,交换头和尾的数据,并将尾的数据删掉,最后从头开始向下调整,使其重新为堆。 

2.6 模拟实现priority_queue的top

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

top就是获取队列首元素的值,我们直接返回下标0的数据即可。

 2.7 模拟实现priority_queue的size和empty

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

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

 priority_queue一样使容器适配器,所以priority_queue的size和empty我们只需返回容器的size和empty即可。

2.8 检验结果

建立大堆:

建立的是大堆,每次输出后重新建堆,所以输出的是降序序列。

建立小堆:

 

 建立的是小堆,每次输出后重新建堆,所以输出的是降序序列

检测size和empty:

 push5个数据,size为5,删除一个后,size为4,empty输出0表示不为空,结果正确。

2.9 模拟实现priority_queue的完整代码

priority_queue.h文件:

#pragma once
#include<iostream>
#include<vector>
#include<functional>
using namespace std;

namespace bit

{
    template<class T>
    struct less
    {
        bool operator()(const T& x, const T& y)
        {
            return x < y;
        }
    };

    template<class T>
    struct greater
    {
        bool operator()(const T& x, const T& y)
        {
            return x > y;
        }
    };


    template <class T, class Container = vector<T>, class Compare = less<T> >

    class priority_queue

    {

    public:

        priority_queue()
        {
        }

        void Adjustdown(size_t parent)
        {
            size_t child = parent * 2 + 1;
            if (child + 1 < c.size() && comp(c[child], c[child + 1]))
            {
                child++;
            }
            while (child < c.size())
            {
                if (comp(c[parent], c[child]))
                {
                    swap(c[parent], c[child]);
                    parent = child;
                    child = parent * 2 + 1;
                }
                else
                {
                    break;
                }
            }
        }

        void Adjustup(size_t child)
        {
            size_t parent = (child - 1) / 2;
            while (child > 0)
            {
                if (comp(c[parent], c[child]))
                {
                    swap(c[parent], c[child]);
                    child = parent;
                    parent = (child - 1) / 2;
                }
                else
                {
                    break;
                }
            }
        }

        template <class InputIterator>

        priority_queue(InputIterator first, InputIterator last)
        {
            while (first != last)
            {
                c.push_back(*first);
                ++first;
            }
            for (size_t i = c.size() - 1 - 1; i >= 0; i--)
            {
                Adjustdown(i);
            }
        }

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

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

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

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

        void pop()
        {
            swap(c[0], c[c.size() - 1]);
            c.pop_back();
            Adjustdown(0);
        }

    private:

        Container c;

        Compare comp;

    };

    void test_priority_queue1()
    {
        priority_queue<int> pq;
        pq.push(1);
        pq.push(3);
        pq.push(7);
        pq.push(0);
        pq.push(9);

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

    void test_priority_queue2()
    {
        priority_queue<int, vector<int>, greater<int>> pq;
        pq.push(1);
        pq.push(3);
        pq.push(7);
        pq.push(0);
        pq.push(9);

        while (!pq.empty())
        {
            cout << pq.top() << " ";
            pq.pop();
        }
        cout << endl;
    }
    
    void test_priority_queue3()
    {
        priority_queue<int> pq;
        pq.push(1);
        pq.push(3);
        pq.push(7);
        pq.push(0);
        pq.push(9);

        cout << pq.size() << endl;
        pq.pop();
        cout << pq.size() << endl;
        cout << pq.empty() << endl;
    }
};

 test.cpp文件:

#include"priority_queue.h"

int main()
{
	//bit::test_priority_queue1();
	//bit::test_priority_queue2();
	bit::test_priority_queue3();
	return 0;
}

三、总结

以上就是模拟实现priority_queue的全部内容,希望以上所讲能够对大家有所帮助,如果对大家有帮助的话,记得一键三连哦,感谢各位。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/872039.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iOS App上架审核被拒——2.3.3 - Performance - Accurate Metadata

iOS上架审核被拒——Guideline 2.3.3 - Performance - Accurate Metadata 噢&#xff0c;又被拒了… 文章目录 iOS上架审核被拒——Guideline 2.3.3 - Performance - Accurate Metadata被拒原因解决 被拒原因 大概翻译了下&#xff1a;预览图问题&#xff0c;只因某张预览图加了…

正则表达式备查

一、常用 符号内容\将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如&#xff0c;“n”匹配字符“n”。“\n”匹配换行符。序列“\”匹配“\”&#xff0c;“(”匹配“(”。^匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性&#xff0c;^ 还…

CSS知识点详解:display+float

display&#xff1a;浮动 1.block&#xff1a;使元素呈现为块级元素&#xff0c;可设置宽高 display: block; 特点&#xff1a;使元素呈现为块级元素&#xff0c;即该元素会以新行开始&#xff0c;占据整行的宽度&#xff0c;即使其宽度未满。 例子&#xff1a; 2.inline&a…

答题小程序的轮播图管理与接入获取展示实现

实现了答题小程序的轮播图管理&#xff0c;包括上传图片、设置轮播图、操作上下线等功能&#xff0c;可用于管理各类答题小程序的轮播图。 轮播图前端接入代码 答题小程序内使用以下代码接入轮播图&#xff1a; WXML&#xff1a; <view style"width: 100%"> …

继承(下)【C++】

文章目录 子类继承父类之后&#xff0c;子类的默认成员函数的变化构造函数编译器自动生成的构造函数程序员手动写的构造函数 拷贝构造编译器自动生成的拷贝构造函数程序员手动写的拷贝构造函数 赋值重载编译器自动生成的赋值重载程序员手动写的赋值重载 析构函数 继承与友元菱形…

ISO 26262中的失效率计算:IEC 61709-Clause 17_Switches and push-buttons

概要 IEC 61709是国际电工委员会&#xff08;IEC&#xff09;制定的一个标准&#xff0c;即“电子元器件 可靠性 失效率的基准条件和失效率转换的应力模型”。主要涉及电学元器件的可靠性&#xff0c;包括失效率的基准条件和失效率转换的应力模型。本文介绍IEC 61709第十七章&…

Linux安装并配置Hadoop

目录 一、安装并配置JDK二、安装并配置Hadoop三、安装过程中遇到的问题总结 一、安装并配置JDK Linux上一般会安装Open JDK,关于OpenJDK和JDK的区别&#xff1a;http://www.cnblogs.com/sxdcgaq8080/p/7487369.html 准备Open JDK 1.8 查询可安装的java版本 yum -y list jav…

C语言第17篇

1.在C语言中,全局变量的存储类别是_________. A) static B) extern C) void D) register 提示&#xff1a;extern adj.外来的 register n.登记表&#xff0c;v.登记 提示与本题无关 2.在一个C源程序文件中,要定义一个只允许本源文件中所有函数使用的全局变…

【经典算法】BFS_最短路问题

目录 1. 最短路问题介绍2. 算法原理和代码实现(含题目链接)1926.迷宫中离入口最近的出口433.最小基因变化127.单词接龙675.为高尔夫比赛砍树 3. 算法总结 1. 最短路问题介绍 最短路径问题是图论中的一类十分重要的问题。本篇文章只介绍边权为1(或边权相同)的最简单的最短路径问…

ant design pro 中用户的表单如何控制多个角色

ant design pro 如何去保存颜色ant design pro v6 如何做好角色管理ant design 的 tree 如何作为角色中的权限选择之一ant design 的 tree 如何作为角色中的权限选择之二ant design pro access.ts 是如何控制多角色的权限的 看上面的图片 当创建或编辑一个用户时&#xff0c;…

自带灭火电池?深蓝SL03托底事故揭秘

近日&#xff0c;网络上的一段热传视频&#xff0c;让不少网友看得先是惊心动魄&#xff0c;然后却又啧啧称奇。 该视频显示&#xff0c;8月18日晚上19点28分&#xff0c;一辆深蓝SL03在行驶中意外遭遇严重托底事故&#xff0c;车辆瞬间腾空跳跃&#xff0c;紧接着底盘出现明火…

禁止浏览器默认填充密码 vue

禁止浏览器默认填充密码会和我的样式冲突 所以禁止 第一种&#xff1a; 通过给表单元素添加 autocomplete"off" 属性&#xff0c; 可以防止浏览器自动填充表单中的账号和密码。可以在 input 标签或整个 form 标签上使用&#xff1a; <template><a-form&g…

向量数据库中的PQ(Procduct Quantization)

为了加快向量之间距离计算和比较速度&#xff0c;有人发明的Product Quantization方法&#xff0c;这个方法并不是一种索引&#xff0c;所以它并不能减少目标向量&#xff08;要查找的向量&#xff09;&#xff0c;与数据库中向量的比较次数&#xff0c;但是它可以加快与每个数…

(第三十三天)

1. 设置主从从 mysql57 服务器 &#xff08; 1 &#xff09;配置主数据库 [rootmsater_5 ~] # systemctl stop filewalld [rootmsater_5 ~] # setenforce 0 [rootmsater_5 ~] # systemctl disable filewalld [rootmsater_5 ~] # ls anaconda-ks.cfg mysql-5.7.44-linux-g…

uniapp 页面跳转传参:父页面监听子页面传过来的数据

父页面 监听events事件 uni.navigateTo({url: "/components/watermark-camera",events: { // 重点重点重点重点重点重点重点重点getImages(data) { // 接收子页面抛出的 getImages 事件console.log("水印相机的照片&#xff1a;", data)}}})子页面 const …

<数据集>航拍牧场奶牛识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1805张 标注数量(xml文件个数)&#xff1a;1805 标注数量(txt文件个数)&#xff1a;1805 标注类别数&#xff1a;1 标注类别名称&#xff1a;[cow] 序号类别名称图片数框数1cow1805141337 使用标注工具&#xff…

World of Warcraft [CLASSIC] the Eye of Eternity [EOE] P1-P2

World of Warcraft [CLASSIC] the Eye of Eternity [EOE] 永恒之眼&#xff08;蓝龙&#xff09; 第一阶段 第二阶段 第三阶段 载具1-6技能介绍 World of Warcraft [CLASSIC] the Eye of Eternity [EOE]_永恒之眼 eoe-CSDN博客 永恒之眼怎么出副本呢&#xff0c;战斗结束&am…

makefile文件基本语法

一、makefile文件基本介绍 Makefile 文件是 make 工具使用的配置文件&#xff0c;它定义了如何自动化构建项目的规则和命令。Makefile 文件的主要作用是指定如何编译和链接程序&#xff0c;以及管理文件之间的依赖关系&#xff0c;从而实现高效的构建过程。 1.1 Makefile 的基…

uniapp微信小程序 分享功能

uniapp https://zh.uniapp.dcloud.io/api/plugins/share.html#onshareappmessage export default {onShareAppMessage(res) {if (res.from button) {// 来自页面内分享按钮console.log(res.target)}return {title: 自定义分享标题,path: /pages/test/test?id123}} }需要再真机…

Appium定位元素

使用工具&#xff1a; 报错: Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException: Remote object doesn‘t 参考链接&#xff1a;Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException: Remote object doesn‘t-CSD…