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

C++学习之路,从0到精通的征途:priority_queue类的模拟实现

目录

一.priority_queue的介绍

二.仿函数

1.仿函数的介绍

2.仿函数的特点

3.实现两个简单的仿函数

三.priority_queue的接口实现

1.成员变量

2.push

3.pop

4.top

5.size

6.empty

7.构造函数

四.代码总览

priority_queue.h

test.cpp


一.priority_queue的介绍

源文档

        在文档中可以看到,对于priority_queue类有三个模板参数,第一个模板参数接收优先队列中的数据类型,第二个模板参数为优先队列的容器适配器,默认为vector,第三个模板参数来接收控制优先级队列为大堆或小堆的仿函数,默认为less,即大堆。

        优先队列其实就可以看作之前学过的数据结构堆。

二.仿函数

1.仿函数的介绍

        仿函数(Functor)也被称作函数对象,它是一种行为类似于函数的对象。要实现仿函数,可通过定义一个类或结构体,并且在其中重载()运算符。如此一来,这个类的对象就能够像函数一样被调用。

2.仿函数的特点

<1>可定制性高:仿函数可依据需求定制其行为,通过重载()运算符实现不同的逻辑。这使得仿函数在算法中能根据具体需求灵活调整行为。

<2>可作为模板参数:在泛式编程里,仿函数可以当作模板参数使用,从而实现通用算法。

3.实现两个简单的仿函数

        以优先队列为例,如果我们想要控制优先队列为大堆或小堆,我们就要实现对应的仿函数:less与greater,优先队列中大堆对应less,小堆对应greater。

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

三.priority_queue的接口实现

1.成员变量

template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
private:Container _con; // 容器适配器Compare com; // 在初始化列表构建仿函数对象
};

2.push

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

        在尾插后进行向下调整算法,由于向下调整与向上调整只在类内部使用,所以定义为私有的成员函数:

void adjustup(size_t child)
{size_t parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

        关于向下调整与向上调整算法的原理,在堆——从理论到代码的深度拆解中有进行讲解,可以前往学习,这里由于通过仿函数进行比较,对于父子结点之间的比较可以通过实例化的仿函数对象进行调用。 

        由于大堆对应less,小堆对应greater,向上和向下调整算法中的比较顺序也要相应调整。

3.pop

void pop()
{std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);
}
void adjustdown(size_t parent)
{size_t child = 2 * parent + 1;while (child < _con.size()){//if (child + 1 < _con.size() && _con[child] < _con[child + 1])if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = 2 * parent + 1;}else{break;}}

4.top

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

5.size

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

6.empty

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

7.构造函数

priority_queue()
{}// 迭代区间构造优先队列
// 遍历,逐个push
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{while (first != last){push(*first);++first;}
}

四.代码总览

priority_queue.h

#include<vector>namespace my_priority_queue
{template<class T>class less{public:bool operator()(const T& x, const T& y){return x < y;}};template<class T>class greater{public: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(){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){push(*first);++first;}}void push(const T& x){_con.push_back(x);adjustup(_con.size() - 1);}void pop(){std::swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}const T& top() const{return _con[0];}size_t size() const{return _con.size();}bool empty() const{return size() == 0;}private:void adjustup(size_t child){size_t parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void adjustdown(size_t parent){size_t child = 2 * parent + 1;while (child < _con.size()){//if (child + 1 < _con.size() && _con[child] < _con[child + 1])if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){child++;}//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = 2 * parent + 1;}else{break;}}}private:Container _con;Compare com; // 在初始化列表构建仿函数对象};
}

test.cpp

#include<iostream>
#include<deque>
using namespace std;#include"priority_queue.h"int main()
{my_priority_queue::priority_queue<int, deque<int>, my_priority_queue::greater<int>> pq1;pq1.push(1);pq1.push(0);pq1.push(8);pq1.push(-1);pq1.push(3);pq1.push(6);while (!pq1.empty()){cout << pq1.top() << " ";pq1.pop();}cout << endl;vector<int> v = { 1,0,8,-1,3,6 };my_priority_queue::priority_queue<int, vector<int>, my_priority_queue::less<int>> pq2(v.begin(), v.end());while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}return 0;
}

http://www.xdnf.cn/news/305047.html

相关文章:

  • Kafka与RocketMQ在事务消息实现上的区别是什么?
  • 扩增子分析|微生物生态网络稳定性评估之鲁棒性(Robustness)和易损性(Vulnerability)在R中实现
  • 鸿蒙系统被抹黑的深层解析:技术、商业与地缘政治的复杂博弈-优雅草卓伊凡
  • 用于备份的git版本管理指令
  • Github Action部署node项目
  • 如何打造系统级低延迟RTSP/RTMP播放引擎?
  • Leetcode Hot 100字母异位词分词
  • spring详解-循环依赖的解决
  • 第九章,链路聚合和VRRP
  • AI+浏览器自动化:Nanobrowser Chrome 扩展的使用「详细教程」
  • 【LLM】Open WebUI 使用指南:详细图文教程
  • Stream和Collections工具类
  • 多行文本省略
  • oceanbase不兼容SqlSugarCore的问题
  • 【KWDB创作者计划】_通过一篇文章了解什么是 KWDB(KaiwuDB)
  • JMeter_配置元件之随机变量(RandomVariable)介绍
  • 手撕算法(1)
  • 使用 Spring Boot 构建 REST API
  • SpringBoot教学管理平台源码设计开发
  • leetcode 24. 两两交换链表中的节点
  • 分库分表后复杂查询的应对之道:基于DTS实时性ES宽表构建技术实践
  • 简说Policy Gradient (1) —— 入门
  • [蓝桥杯 2025 省 B] 水质检测(暴力 )
  • python--------修改桌面文件内容
  • 第2章 神经网络的数学基础
  • 神经网络之激活函数:解锁非线性奥秘的关键
  • Linux开发工具【上】
  • 2025年LangChain(V0.3)开发与综合案例
  • 接口自动化工具如何选择?以及实战介绍
  • windows操作系统开机自启(自动启动) 运行窗口 shell:startup 指令调出开机自启文件夹