【C++】stack/queue/优先级队列的模拟实现

目录

  • 1. stack/queue
    • 1.1 模拟实现
  • 2. 优先级队列
    • 2.1 模拟实现
    • 2.2 仿函数

1. stack/queue

stack文档说明

queue文档说明

stack和queue被称为容器适配器。

容器适配器是什么?
它是一种特殊的容器类型,通过封装已有的容器类型来提供特定功能的接口函数,以满足不同的需求。

而stack和queue底层封装的是deque容器。

deque(双端队列)容器不仅支持头部和尾部数据的插入和删除,也支持随机存取、访问和修改(迭代器),但是每个方面的功能又不是特别突出,尤其是随机存取和中间位置插入删除数据,效率比较低,因此很少单独使用deque,而且将其作为某个容器的适配器。

stack和queue的结构特性都是只能在两端进行数据的操作,无需随机存取和中间位置插入删除,因此用deque来适配就非常合适。

1.1 模拟实现

#include <iostream>
#include <deque>
using namespace std;
namespace lzh {//stack//第二个模板参数默认使用dequetemplate<class T, class Container = deque<T>>class stack {public:void push(const T& x) {_con.push_back(x);}void pop() {_con.pop_back();}T& top() {return _con.back();}const T& top() const {return _con.back();}size_t size()const {return _con.size();}bool empty()const {return _con.empty();}private:Container _con;};//queuetemplate<class T, class Container = deque<T>>class queue {public:void push(const T& x) {_con.push_back(x);}void pop() {_con.pop_front();}T& front() {return _con.front();}T& back() {return _con.back();}const T& front() const {return _con.front();}const T& back()	const {return _con.back();}size_t size()const {return _con.size();}bool empty()const {return _con.empty();}private:Container _con;};
}

2. 优先级队列

priority_queue文档说明

priority_queue是一种特殊的队列,它可以根据元素的优先级(或者大小)自动进行排序,并且优先级最高的先出队

本质是二叉堆结构

在这里插入图片描述
它也是一个容器适配器,底层封装了vector容器,并且元素的优先级是通过第三个模板参数仿函数来控制的

在这里插入图片描述默认是大堆 - less<T>,若想实现小堆则要显式传递三个参数封装的容器类型和仿函数:

在这里插入图片描述

2.1 模拟实现

#pragma once
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
namespace lzh {template<class T, class Container = vector<T>>class priority_queue {void adjustDown(int fatherIdx) {int childIdx = fatherIdx * 2 + 1;while (childIdx < (int)_con.size()) {if (childIdx + 1 < (int)_con.size() && _con[childIdx + 1] > _con[childIdx]) {++childIdx;}if (_con[childIdx] > _con[fatherIdx]) {swap(_con[childIdx], _con[fatherIdx]);fatherIdx = childIdx;childIdx = fatherIdx * 2 + 1;}else {break;}}}void adjustUp(int childIdx) {int fatherIdx = (childIdx - 1) / 2;while (childIdx > 0 && _con[childIdx] > _con[fatherIdx]) {swap(_con[childIdx], _con[fatherIdx]);childIdx = fatherIdx;fatherIdx = (childIdx - 1) / 2;}}public:priority_queue() { }template <class InputIterator>priority_queue(InputIterator first, InputIterator last) {while (first != last) {_con.push_back(*first);++first;}for (int i = (_con.size() - 2) / 2; i >= 0; --i) {adjustDown(i);}}bool empty() const {return _con.empty();}size_t size() const {return _con.size();}// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性const T& top() const {return _con.front();}void push(const T& x) {_con.push_back(x);adjustUp(_con.size() - 1);}void pop() {swap(_con.front(), _con.back());_con.pop_back();adjustDown(0);}private:Container _con;};
}

2.2 仿函数

默认实现的是大堆,因为比较那里写死了,若要实现小堆结构则需要修改向下和向上调整算法的比较逻辑,但实际上库里实现的优先级队列是没办法修改的,所以真正的做法是使用仿函数作为第三个模板参数传递给容器,来实现大小堆的切换。

仿函数本质是一个类类型,类中重载了()运算符:

//仿函数且类模板
template<class T>
class Less {
public://若为自定义类型则该类中实现了小于运算符重载bool operator()(const T& x, const T& y) {return x < y;}
};void test_less() {//函数对象Less lessFunc;cout << lessFunc(1, 2) << endl;//显式调用//cout << lessFunc.operator()(1, 2) << endl;
}

可以发现该对象可以像函数一样来使用。

类似于C语言中的函数指针

用仿函数来灵活调整调整算法的逻辑,控制是大堆还是小堆:

using namespace std;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;}
};namespace lzh {template<class T, class Container = vector<T>, class Compare = less<T>>class priority_queue {void adjustDown(int fatherIdx) {//定义仿函数对象Compare cmp;int childIdx = fatherIdx * 2 + 1;while (childIdx < (int)_con.size()) {//通过函数对象进行比较if (childIdx + 1 < (int)_con.size() &&cmp(_con[childIdx], _con[childIdx + 1])) {++childIdx;}//通过函数对象进行比较if (cmp(_con[fatherIdx], _con[childIdx])) {swap(_con[fatherIdx], _con[childIdx]);fatherIdx = childIdx;childIdx = fatherIdx * 2 + 1;}else {break;}}}void adjustUp(int childIdx) {//定义仿函数对象Compare cmp;int fatherIdx = (childIdx - 1) / 2;while (childIdx > 0 && cmp(_con[fatherIdx], _con[childIdx])) {swap(_con[fatherIdx], _con[childIdx]);childIdx = fatherIdx;fatherIdx = (childIdx - 1) / 2;}}//...其他成员}
}
int main() {//第三个模板参数//Less默认是建大堆//而Greater是建小堆//和库里的实现一致//第二和第三个模板参数有缺省值//若要大堆,可以只传第一个元素类型//而要小堆则三个都需要传递lzh::priority_queue<int, vector<int>, Less<int>> pq;pq.push(3);pq.push(5);pq.push(1);pq.push(4);while (!pq.empty()) {cout << pq.top() << ' ';pq.pop();}cout << endl;return 0;
}

通过传递不同的仿函数类型,便可以控制是建大堆还是小堆。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP 报修管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 报修管理系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载地址&#xff1a; https://download.csdn.net/download/qq_41221322/88209950 视…

postgresql 谨慎使用正则删除(%,_)

建表 CREATE TABLE public.ellistest (id bigserial NOT NULL,"name" varchar null,primary key (id) );插入数据 删除含有_线的数据 你会发现表被清空了 delete from ellistest where name like %_%原因 百分号(%)用于表示0、1或多个字符或数字。 下划线通配符…

Redis 数据持久化

官方文档&#xff1a;https://redis.io/docs/management/persistence/ Redis提供了主要提供了 2 种不同形式的持久化方式&#xff1a; RDB&#xff08;Redis数据库&#xff09;&#xff1a;RDB 持久性以指定的时间间隔执行数据集的时间点快照。 AOF&#xff08;Append Only F…

广州华锐互动:3D数字孪生开发编辑器助力企业高效开发数字孪生应用

3D数字孪生开发编辑器是一种新兴的技术&#xff0c;它可以帮助企业更好地管理和维护其物联网设备。这些工具可以帮助企业实现对设备的实时监控、故障排除和优化&#xff0c;从而提高生产效率和降低成本。 数字孪生系统是一种将物理世界与数字世界相结合的技术&#xff0c;它可以…

35_windows环境debug Nginx 源码-CLion配置CMake和启动

文章目录 生成 CMakeLists.txt 组态档35_windows环境debug Nginx 源码-CLion配置CMake和启动生成 CMakeLists.txt 组态档 修改auto目录configure文件,在 . auto/make 上边增加 . auto/cmake, 大概在 106 行。在 auto 目录下创建cmake 文件其内容如下: #!/usr/bin/env bash NG…

历数浙大MPA提前批面试的三大变化

从2019年招生开始&#xff0c;浙大mpa项目的招生趋势一直处于稳增状态&#xff0c;特别是提前批面试政策的出现&#xff0c;更加为项目的整体招录添上神奇的一笔。为什么要举行提面&#xff1f;一方面报考的人数比较多&#xff0c;有了选拔的余地和基础&#xff1b;另一方面也能…

JSP-学习笔记

文章目录 1.JSP介绍2 JSP快速入门3 JSP 脚本3.1 JSP脚本案例3.2 JSP缺点 4 EL表达式4.1 快速入门案例 5. JSTL标签6. MVC模式和三层架构6.1 MVC6.2 三层架构 7. 案例-基于MVC和三层架构实现商品表的增删改查 1.JSP介绍 概念 JSP&#xff08;JavaServer Pages&#xff09;是一种…

c++ | 字节转换 | 字长 | 机器位数

为什么有的时候脑子转不过来&#xff1f;&#xff1f; 为什么要对字节、机器长啊、位啊都要门清 位数 一般的就是指计算机的位数&#xff0c;比如64位/32位&#xff0c;更简单的理解&#xff0c;计算机就是在不停的做二进制的计算&#xff0c;比如32位计算机&#xff0c;在长…

【运筹优化】贪心启发式算法和蜘蛛猴优化算法求解连续选址问题 + Java代码实现

文章目录 一、问题描述二、思路分析三、解决方案3.1 贪心启发式算法3.2 群体智能算法&#xff08;蜘蛛猴优化算法&#xff09; 四、总结 一、问题描述 选址问题是指在规划区域里选择一个或多个设施的位置&#xff0c;使得目标最优。 按照规划区域的结构划分&#xff0c;可以将…

PHP自己的框架实现function引入和dump函数(完善篇一)

1、实现效果 2、创建三个function.php 3、文件加载&#xff08;KJ.php&#xff09; 定义目录 define("FILE_PATH",KJ_CORE./file); //定义框架文件路径define("COMMON_PATH",ROOT_PATH./common); //定义公共目录 加载文件 public static function run(){…

C# 读取pcd、ply点云文件数据

最近研究了下用pcl读取点云数据&#xff0c;又做了个C#的dll&#xff0c;方便读取&#xff0c;同样这个dll基于pcl 最新版本1.13.1版本开发。 上次做的需要先得到点云长度&#xff0c;再获取数据。这次这个定义了一个PointCloudXYZ类来存数据。将下面的dll拷贝到可执行目录下&a…

HackNos 3靶场

配置 进入控制面板配置网卡 第一步&#xff1a;启动靶机时按下 shift 键&#xff0c; 进入以下界面 第二步&#xff1a;选择第二个选项&#xff0c;然后按下 e 键&#xff0c;进入编辑界面 将这里的ro修改为rw single init/bin/bash&#xff0c;然后按ctrlx&#xff0c;进入…