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

server/2024/9/25 21:19:48/

一、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.ppmy.cn/server/104313.html

相关文章

MiDaS、ZoeDepth、Depth-Anything ai算法深度图估计

1、MiDaS 参考&#xff1a; https://github.com/isl-org/MiDaS https://pytorch.org/hub/intelisl_midas_v2/ https://colab.research.google.com/github/pytorch/pytorch.github.io/blob/master/assets/hub/intelisl_midas_v2.ipynb#scrollTo5A32CL3tocrZ 代码 import cv2 i…

Spring 中的AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext 是 Spring Framework 中用于支持基于注解的 Web 应用程序配置的类&#xff0c;位于 org.springframework.web.context.support 包中。它是 GenericWebApplicationContext 的一个实现&#xff0c;允许通过使用 Java 注解来设置和管理 Spr…

鹏哥C语言自定义笔记重点(29-)

29.函数指针数组 30.void指针是不能直接解引用&#xff0c;也不能-整数。 void*是无具体类型的指针&#xff0c;可以接受任何类型的地址。 31.qsort:使用快速排序的思想实现一个排序函数(升序) 32. 33.地址的字节是4/8 34.char arr[]{a,b} sizeof(arr[0]1)答案是4&#xff0…

[000-01-022].第03节:RabbitMQ中的优先级队列

9.2. 优先级队列 9.2.1. 使用场景 1在我们系统中有一个订单催付的场景&#xff0c;我们的客户在天猫下的订单,淘宝会及时将订单推送给我们&#xff0c;如果在用户设定的时间内未付款那么就会给用户推送一条短信提醒&#xff0c;很简单的一个功能对吧&#xff1b;2.但是上述情…

网络编程,网络协议,UDP编程

网络&#xff1a; 1.协议&#xff1a;通信双方约定的一套标准 2.国际网络通信协议标准&#xff1a; 1.OSI协议&#xff1a; 应用层 发送的数据内容 表示层 数据是否加密 会话层 是否建立会话连接 传输层 …

Android12 MTK 去掉多用户

1、需求&#xff1a; &#xff08;1&#xff09;去掉设置中系统–多用户 &#xff08;2&#xff09;去掉下拉菜单中多用户按钮 2、解决 路径&#xff1a;***/frameworks/base/core/java/android/os/UserManager.java /*** Returns whether this device supports multiple …

Windows上的瑞士军刀-Microsoft Powertoys

Windows上的瑞士军刀-Microsoft Powertoys Microsoft PowerToys 是一组实用工具&#xff0c;可帮助高级用户调整和简化其 Windows 体验&#xff0c;从而提高工作效率。PowerToys 并非什么新鲜事物&#xff0c;早在 windows 95 时代就已经存在。20年后&#xff0c;于 2020 年才…

MySQL的聚合函数的查询语句

1. COUNT函数 COUNT函数用于计算指定列中的行数。以下是COUNT函数的基本语法&#xff1a; SELECT COUNT(列名) FROM 表名; 例如&#xff0c;我们可以使用以下SELECT语句计算表中客户的总数&#xff1a; SELECT COUNT(*) AS total_customers FROM customers; 2. SUM函数 …