当前位置: 首页 > 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;
}

相关文章:

  • 20250506异形拼图块(圆形、三角、正方,椭圆/半圆)的中2班幼儿偏好性测试(HTML)
  • 高频面试题:设计秒杀系统,用Redis+Lua解决超卖
  • SpringBoot教学管理平台源码设计开发
  • [学习]RTKLib详解:pntpos.c与postpos.c
  • C++【继承】
  • 深入浅出数据库事务:原子性、一致性、隔离性、持久性
  • ShardingSphere:使用information_schema查询时报错:Table ‘数据库名称.tables‘ doesn‘t exist
  • 荣耀A8互动娱乐组件部署实录(终章:后台配置系统与整体架构总结)
  • 【Linux系统篇】:Linux线程同步---条件变量,信号量与CP模型实现
  • Qt学习Day0:Qt简介
  • 【C语言】(7)—指针1
  • ActiveMQ 安全机制与企业级实践(一)
  • next中的server comonent中如何共享session
  • 2025 后端自学UNIAPP【项目实战:旅游项目】1、创建项目框架
  • 物理服务器紧急救援:CentOS系统密码重置全流程实战指南
  • 关于论文中插入公式但是公式相对于段落的位置偏上应该如何调整备份
  • UE5 GAS开发P47 游戏标签
  • STL?string!!!
  • 【Hive入门】Hive安全管理与权限控制:审计日志全解析,构建完善的操作追踪体系
  • 【大数据】服务器上部署Apache Paimon
  • 印巴矛盾已达近年“最高点”:军政经文全面紧张,巴将向联合国通报局势
  • 【社论】跑赢12级狂风,敦煌做对了什么
  • 马克思主义理论研究教学名师系列访谈|石书臣:思政课是落实立德树人的关键
  • 新质观察|“模速空间”如何成为“模范空间”
  • 2年就过气!ChatGPT催生的百万年薪岗位,大厂不愿意招了
  • 巴基斯坦宣布禁止印度船只入港