C++学习——优先级队列模拟实现与仿函数初步认识

news2024/10/7 14:34:09

目录

​编辑

一,优先级队列

二,实现

1.构造priority_queue类

2.简单的top()与size()还有empty()函数

3.push函数

4.pop函数

5.构造函数

6.测试

三,仿函数

1.介绍

 2.使用


 

一,优先级队列

优先级队列——priority_queue。这个结构体类型也是C++里面的一个非常好用的一个数据结构。可以在Cplusplus网站上看看这个数据结构的介绍:

在这一项介绍中可以看到这个数据结构类型的各种模板。因为我们要实现一个priority_queue所以我们就要来看看这个数据结构类型的各种函数,如下:

今天我们只会实现size,top,push,pop,还有一个construct的迭代器构造函数。在这里还要声明一点,这个数据结构类型的地城原理其实就是一个堆,也就是heap。

二,实现

1.构造priority_queue类

实现步骤如下,首先开一个.h文件。然后写下如下代码:

#include<iostream>  
  2 using namespace std;  
  3   
  4 namespace area  
  5 {
  6   template<class T,class Container>
  7   class priority_queue
  8   {
  9     public:                                                                                                                                                                            
 10                    
 11                                                                                      
 12     private:                                                                         
 13       Container _con;                                                                
 14                                                                                      
 15   };                                                                                 
 16                                                                                      
 17 }       

因为这个优先级队列实现的原理和堆实现的原理相像,所以可以先传一个缺省参数vector<T>给Container。如下:

#include<iostream>  
  2 using namespace std;
  3 #include<vector> 
  4 
  5 namespace area
  6 {
  7   template<class T,class Container=vector<T> >
  8   class priority_queue
  9   {
 10     public:
 11                                                                                                                                                                                        
 12 
 13     private:
 14       Container _con;                                                                 
 15                                                                                       
 16   };                                                                                  
 17                                                                                       
 18 }           

2.简单的top()与size()还有empty()函数

这两个函数实现起来比较简单,所以可以先来实现一下,实现代码如下:

#include<iostream>  
  2 using namespace std;  
  3 #include<vector>  
  4   
  5 namespace area  
  6 {  
  7   template<class T,class Container=vector<T> >  
  8   class priority_queue  
  9   {  
 10     public:  
 11     const T&  top()//top函数
 12     {
 13       return _con[0];
 14     }
 15 
 16     size_t size()//size()函数
 17     {
 18       return _con.size();
 19     }
 20     
 21     bool empty()//empty()函数
 22     {
 23       return _con.size()==0;                                                                                                                                                           
 24     }                                                                                                                                                                           
 25     private:                                                                                                                                                                    
 26       Container _con;                                                                                                                                                           
 27                                                                                                                                                         
 28   };                                                                                                                                                    
 29                                                                                                                                                         
 30 }                                                                                                                                                       
~                         

在这里复习一个知识点,top函数能使用引用传参的条件是_con[0]出了top函数的作用域以后没有被销毁。

3.push函数

因为我们要模仿的是堆排序的模式,所以在实现push函数的同时就得实现一个向上调整建堆。向上调整建堆的代码如下:

 void adjust_up(int child)  
 27    {         
 28      size_t parent = (child-1)/2;  
 29      while(child>0)  
 30      {               
 31         if(_con[child]<_con[parent])  
 32         {  
 33           swap(_con[child],_con[parent]);//模板数据结构里面已经实现这个swap()函数。  
 34           child = parent;  
 35           parent = (child-1)/2;  
 36         }  

 37         else  
 38         {  
 39           break;                                                                                                                                                                       
 40         }                                                                                                                                                                             
 41      }                                                                                                                                                                                
 42    }      

然后在push调用的时候便是这样使用的:

  void push(T& x)                                                                                                                                                                   
 45     {                                                                                                                                                                                 
 46       _con.push_back(x);                                                                                                                                                              
 47       adjust_up(_con.size()-1);                                                                                                                                                       
 48     }    

当然,这段代码不能让这个堆的每个下标的大小都是符合顺序的但是可以保证这个vector类型的数组是一个堆。

4.pop函数

pop函数的实现也要依靠一个向下调整的函数。这个向下调整的函数实现代码如下:

  void adjust_down(int parent)
 51     {
 52       int child = parent*2+1;
 53       while(child<_con.size())
 54       {
 55         if(child+1<_con.size()&&_con[child+1]<_con[child])
 56         {
 57           child++;
 58         }
 59         if(_con[child]<_con[parent])
 60         {
 61           swap(_con[child],_con[parent]);
 62           parent = child;
 63           child = parent*2+1;
 64         }
 65         else
 66         {
 67           break;
 68         }
 69 
 70       }
 71     }
   

然后我们再来实现pop()函数:

 void pop()
 74     {
 75       swap(_con[0],_con[_con.size()-1]);
 76       _con.pop_back();
 77       adjust_down(0);
 78     }

经过上述操作,我们的pop函数就写好了。

5.构造函数

1.迭代器构造函数:

 template<class InputIterator>                                                    
 36       priority_queue(InputIterator first,InputIterator last)                         
 37       :_con(first,last) //调用模板容器的迭代器构造函数                                                             
 38       {                                                                                                                                                              
 39         for(int i=(_con.size()-1-1)/2;i>=0;i--)                                                                                                                      
 40         {                                                                                                                                                            
 41           adjust_down(i); //从最后一个父节点开始调整成堆                                                                                                                                           
 42         }                                                                                                                                                            
 43       }      

这个迭代器区间构造函数其实是十分好写的,因为我们调用的容器里面已经实现了迭代器区间构造函数,我们复用便可以了。但是这里要注意一个点,就是在我们写下这个迭代器区间构造函数以后,默认生成的无参的构造函数就没有了。所以我们就得加一个无参的构造函数:

  priority_queue()              
 31    {                                                        
 32                        
 33    }  

6.测试

我们再创建一个.cc文件,写入以下代码:

#include"priority_queue.h"
  2 
  3 int main()
  4 {
  5   area::priority_queue<int>q;
  6   q.push(4);
  7   q.push(3);
  8   q.push(9);
  9   q.push(10);
 10   q.push(40);
 11   q.push(99);
 12   q.push(12);
 13   q.push(9);
 14 
 15   while(!q.empty())
 16   {
 17     cout<<q.top()<<" ";
 18     q.pop();
 19   }
 20 
 21   cout<<endl;                                                                                                                                                                          
 22   return 0;
 23 }

运行结果如下:

得到这样的结果说明我们的优先级队列是写对了的。

三,仿函数

1.介绍

在上面的代码中,我们实现的是一个小堆但是如果我们要实现一个大堆呢?难道我们要改代码吗?我们当然是不用的,可以仿照qsort函数的实现手法:

在这个函数实现的时候会有一个compar函数,这个函数是函数指针类型的我们可以通过这个写这个函数的逻辑来实现按顺序排还是按逆序排。在实现优先级队列时我们也可以根据这个思想来实现相同的控制效果。但是在Cpp中是非常鄙视函数指针的。所以我们得用到一个叫做仿函数的知识。仿函数如下:

template<class T>  
  5 class Less  
  6 {  
  7  bool  operator()(const T&x,const T&y)  
  8   {  
  9     return x<y;  
 10   }  
 11 };  
 12   
 13 template<class T>  
 14 class Greater  
 15 {  
 16   bool operator()(const T&x,const T&y)  
 17   {  
 18     return x>y;
 19   }
 20 };

这样便实现了两个仿函数了。可以看到仿函数其实不是一个函数,只不过是在一个类里面将

()重载,从而让这个类可以像函数一样使用,所以才叫做仿函数。

 2.使用

实现了以上两个仿函数以后,我们便要开始在我们模拟实现的优先级队列里使用这个仿函数了。首先我们得在模板里面再添加一个模板参数compare,如下:

 template<class T,class Container=vector<T>,class compare = Less<T> >   

并且默认生成的是小堆。然后我们再来一些替换,将比较的地方换成仿函数的对象。所以我们要先造一个仿函数对象:

 compare com;

然后将比较的地方替换成仿函数便可以了,如以下地方:

if(child+1<_con.size()&&com(_con[child+1],_con[child]))
 78         {
 79           child++;
 80         }
 81         if(com(_con[child],_con[parent]))
 82         {
 83           swap(_con[child],_con[parent]);
 84           parent = child;
 85           child = parent*2+1;
 86         }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】gnustl_static 与 c++_shared 的区别

参考&#xff1a;GNU与cSTL的区别与联系-爱代码爱编程​ gnustl_static 与 c_shared 的区别&#xff1a; 不同版本的 STL TSL是一个与STL兼容的多线程支持库。 STLport是一个可移植、高度兼容的STL实现。 SGI STL是最早的STL实现之一&#xff0c;对STL的发展起到了重要的作用…

深入MySQL数据库进阶实战:性能优化、高可用性与安全性

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 MySQL是世界上最流行的开…

Windows 下 MySQL 8.1.0 安装及配置图文指南,快速搭建实验学习环境

目录 下载 MySQL安装 MySQL配置 MySQL修改密码配置环境变量 卸载 MySQL开源项目微服务商城项目前后端分离项目 下载 MySQL 访问 MySQL 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 下载 MySQL 时&#xff0c;你可以选择 ZIP 包或 MSI 安装&#xff1a; ZIP包…

赴日IT课程分享 如何尽快就职日本IT公司?

想要做赴日IT工作&#xff0c;我们先要搞清楚一个问题&#xff0c;那就是日本IT行业的缺口真的很大吗&#xff1f;答案是肯定的&#xff0c;对于有3-5年实际开发经验&#xff0c;能独立做开发&#xff0c;日语口语也好&#xff0c;不需要协助就能独立跟日本人交流的人&#xff…

DeepFace【部署 01】轻量级人脸识别和面部属性分析框架安装使用详解(网盘分享模型文件)

DeepFace安装使用 1.安装1.1 官方的三种方式1.2 使用的方式 2.使用2.1 模型文件下载2.2 Facial Recognition2.3 Face Verification2.4 Face recognition2.5 Embeddings2.6 Face recognition models2.7 Similarity2.8 Facial Attribute Analysis2.9 Face Detectors 3.总结 Githu…

知网G4期刊-基础教育论坛-如何投稿?

《基础教育论坛》知网 3版5000字符 24年上半年刊期&#xff0c;可收中小学基础教育&#xff0c;幼儿教育等教育全科文章。 《基础教育论坛》主要刊登有关教育教学理论探讨及课程改革、教学改革、考试改革研究等方面的文章&#xff0c;为广大基础教育工作者提供学术交流的…

Lua学习笔记:debug.sethook函数

前言 本篇在讲什么 使用Lua的debug.setHook函数 本篇需要什么 对Lua语法有简单认知 依赖Sublime Text工具 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全流程的源码内容 ★提高阅读体验★ &#x1f449; ♠ 一级标题 &…

第五章:C语言的数组

文章目录 1、数组的理解2、各类数组的定义3、变长数组4、字符数组 1、数组的理解 一维数组&#xff1a;比如定义一个int a[3];,那么可以将其看成两部分&#xff0c;a【3】为①&#xff0c;int为②。意思就是有一个数组名字为a&#xff0c;里面包含3个&#xff08;池&#xff0…

QT5自定义下拉框为QTreeView类型(树形分上下级)的下拉框(QComboBox)(超详细步骤)

项目开发中&#xff0c;很可能简单的QComboBox满足不了需求&#xff0c;就需要自定义QComboBox。 先看效果。 自定义ComboBox 1、先建立一个project&#xff0c;命名为CustomComboBox,建立一个project的过程不细说了。建立后的工程目录如下图&#xff1a; 2、在项目名CustomCo…

React 全栈体系(十六)

第八章 React 扩展 五、Context 1. 代码 /* index.jsx */ import React, { Component } from react import ./index.css//创建Context对象 const MyContext React.createContext() const {Provider,Consumer} MyContext export default class A extends Component {state …

蓝桥杯每日一题20223.9.26

4407. 扫雷 - AcWing题库 题目描述 分析 此题目使用map等都会超时&#xff0c;所以我们可以巧妙的使用哈希模拟散列表&#xff0c;哈希表初始化为-1首先将地雷读入哈希表&#xff0c;找到地雷的坐标在哈希表中对应的下标&#xff0c;如果没有则此地雷的位置第一次出现&#…

2023彩虹商城自助发卡商城+卡卡云模板+wxstore模板

2023彩虹商城自助发卡商城免授权版卡卡云模板wxstore模板 全新SUP模板/知识付费模板/卡卡云模板&#xff0c;首页美化&#xff0c;登陆页美化&#xff0c;修复了pc端购物车页面显示不正常的问题。

RabbitMQ的工作模式——WorkQueues模式

1.工作队列模式 生产者代码 public class Producer_WorkQueues1 {public static void main(String[] args) throws IOException, TimeoutException {//1.创建连接工厂ConnectionFactory factory new ConnectionFactory();//2.设置参数factory.setHost("172.16.98.133&qu…

动态线程池框架DynamicTp v1.1.4大版本发布,新增若干实用特性

DynamicTp 简介 DynamicTp 是一个基于配置中心实现的轻量级动态线程池监控管理工具&#xff0c;主要功能可以总结为动态调参、通知报警、运行监控、三方包线程池管理等几大类。 DynamicTp 特性 代码零侵入&#xff1a;我们改变了线程池以往的使用姿势&#xff0c;所有配置均放…

【算法】直接插入排序

文章目录 概念实现过程时间复杂度和空间复杂度代码示例 总结 概念 直接插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法&#xff0c;它的基本思想是通过构建有序的子序列&#xff0c;逐步将无序的元素插入到有序序列中&#xff0c;最终实现整体的排序…

【python基础】—内置模块os常用功能介绍

文章目录 前言一、模块变量os.nameos.environ 二、文件与文件夹os.getcwd(path)os.chdir(path)os.listdir(path)os.mkdir(path)os.remove(path)os.rename(src,dst) 三、os的子模块&#xff1a;Path模块os.path.abspath(path)os.path.basename(path)os.path.dirname(path)os.pat…

软件设计模式——桥接模式

摘要 桥接模式(Bridge pattern): 使用桥接模式通过将实现和抽象放在两个不同的类层次中而使它们可以独立改变。 一、桥接模式的意图 将抽象与实现分离开来&#xff0c;使它们可以独立变化。 二、桥接模式的类图 Abstraction: 定义抽象类的接口Implementor: 定义实现类接口 …

C++标准模板(STL)- 输入/输出操纵符-(std::resetiosflags,std::setiosflags)

操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符&#xff08;例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; &#xff09;实现为接受到流的引用为其唯一参数的函数。 basic_ostream::…

【计算机视觉】3.传统计算机视觉方法

传统计算机视觉方法 一、大纲图像分割人脸检测行人检测 二、图像分割基于阈值检测的方法基于边缘检测的方法基于区域的分割方法基于图论的分割方法 三、人脸检测四、行人检测五、SVM六、DPM 一、大纲 图像分割 基于阈值、基于边缘 基于区域、基于图论 人脸检测 Haar-like 特征…

渗透测试之——信息收集思路

请遵守网络安全法 渗透测试时要和客户定好时间再使用扫描器。 渗透测试切记不要渗透客户所给域名的同级域名&#xff0c;可以渗透所给域名的子域名。信息收集永远是渗透测试的第一步。 1. 测试目标 xiusafe.com 2. 域名与ip 渗透测试中IP比域名更适合做渗透&#xff1b; …