C++:STL--priority_queue

news/2024/11/24 11:02:00/

在这里插入图片描述

文章目录

  • 一.STL设计思想:容器适配器
      • STL--stack的代码设计
      • STL--queue的代码设计
      • stack和queue的默认容器适配器deque的数据结构解析
        • deque的存储结构示意图
  • 二.C++仿函数
      • 仿函数示例
  • 三.STL--priority_queue(优先级队列)
      • 1.C++优先级队列的数据结构
      • 2.priority_queue的实现框架
        • 比较函数(仿函数)的设计
        • priority_queue类模板实例化示例
      • 3.堆的向上调整接口实现
      • 4.堆的向下调整接口实现
      • 5.priority_queue类模板

一.STL设计思想:容器适配器

在STL的实现中,经常会复用已经完成实现的容器去实现另外一种容器(代码复用思想的具体体现),此时,前者(已经完成实现的容器)就称为后者(待实现的容器)的容器适配器,容器适配器的类型在代码设计中作为待实现容器的类模板参数.
比如,STL的stack和queue就是利用容器适配器思想来实现的

STL–stack的代码设计

template<class T, class container = deque<T>>
class stack
{
public:stack() {}void push(const T& x) {_c.push_back(x);}void pop() {_c.pop_back();}T& top() { return _c.back();}const T& top()const {return _c.back();}size_t size()const {return _c.size();}bool empty()const {return _c.empty();}
private:container _c;
};

STL–queue的代码设计

template<class T, class container = deque<T>>
class queue
{
public:queue() {}void push(const T& x) { _c.push_back(x); }void pop() { _c.pop_front(); }T& back() { return _c.back(); }const T& back()const { return _c.back(); }T& front() { return _c.front(); }const T& front()const { return _c.front(); }size_t size()const { return _c.size(); }bool empty()const { return _c.empty(); }
private:container _c;
};
  • 在这里插入图片描述
  • 根据stack和queue的实现框架可知,它们容器适配器必须支持数据的尾插,尾删, 头插,头删等等操作,用类型不合适的容器适配器去实例化stack和queue无法通过编译

stack和queue的默认容器适配器deque的数据结构解析

deque是STL标准库中的双端队列,其存储结构是用指针数组管理的一系列数组集合,它同时支持时间复杂度为O(1)的数据头插头删,尾插尾删操作

deque的存储结构示意图

  • 在这里插入图片描述
  • 分析deque的存储结构易知:deque的元素随机访问(下标访问)操作运算量较大,因此效率不高,而且在deque容器的中间位置插入或删除元素性能消耗非常巨大,而且deque的迭代器实现非常复杂
  • 因此有以下结论:
    • deque非常适合进行数据的头尾插入和删除操作,因此可以作为stack和queue的默认适配容器
    • 当使用场景涉及在容器的中间位置插入或删除元素时,首选list,使用deque效率会非常低
    • 当算法需要大量的元素随机访问操作时(比如快排),优先使用vector

二.C++仿函数

C++中的仿函数实质上是将()运算符重载封装在类中,使被封装起来的函数其可以依托于类对象作为"函数形参"传入其他函数中进行调用,C++设计仿函数的目的是为了取代C语言中的函数指针,有效地提高了代码的封装性

仿函数示例

  • 基于仿函数设计出来的两个数据比较函数
	template<class DataType>class less{public:bool operator()(const DataType& data1, const DataType& data2){return data1 < data2;}};template<class DataType>class greater{public:bool operator()(const DataType& data1, const DataType& data2){return data1 > data2;}};
  • 调用示例:
  • 在这里插入图片描述

三.STL–priority_queue(优先级队列)

1.C++优先级队列的数据结构

  • priority_queue的逻辑结构是一颗完全二叉树,其存储结构一般采用vector作为其默认容器适配器(容器适配器类型可由用户来决定,然而由于堆的上下调整算法涉及频繁的元素随机访问操作,因此大多数情况下vector都是priority_queue的最佳容器适配器)
    在这里插入图片描述

2.priority_queue的实现框架

	template<class DataType, class Container = std::vector<DataType>, class Compare = less<DataType>>class priority_queue{public:// 创造空的优先级队列priority_queue() {};//用迭代器区间建堆,采用元素向下调整法建堆template<class Iterator>priority_queue(Iterator first, Iterator last);//堆插入接口void push(const DataType& data);//堆顶元素出队接口void pop();//返回队列元素个数的接口size_t size()const;//队列判空接口bool empty()const;// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性const DataType& top()const;private://元素向上调整接口void AdjustUP(int child);//元素向下调整接口void AdjustDown(int parent);}private://储存堆的物理容器Container _array;};
  • priority_queue类模板首部分析:
    在这里插入图片描述

比较函数(仿函数)的设计

	//用仿函数来实现比较器,用于控制堆的类型//用于建大堆的比较函数template<class DataType>class less{public:bool operator()(const DataType& data1, const DataType& data2) const{return data1 < data2;}};//用于建小堆的比较函数template<class DataType>class greater{public:bool operator()(const DataType& data1, const DataType& data2) const{return data1 > data2;}};
  • less<DataType>来实例化priority_queue的Compare模板参数则建立大根堆
  • greater<DataType>来实例化priority_queue的Compare模板参数则建立小根堆

priority_queue类模板实例化示例

在这里插入图片描述

3.堆的向上调整接口实现

  • 图解以小根堆为例:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
		//元素向上调整接口void AdjustUP(int child){//创建数据比较函数(仿函数类)Compare comparator;int parent = (child - 1) / 2;while (child > 0){if (comparator(_array[parent] , _array[child])){std::swap(_array[child], _array[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}

4.堆的向下调整接口实现

  • 堆的向下调整动图:
    在这里插入图片描述
		//元素向下调整接口void AdjustDown(int parent){//创建数据比较函数(仿函数类)Compare comparator;//先取左孩子int child = 2 * parent + 1;while (child < size()){//取出左右孩子的较大值(或较小值)if (child + 1 < size() && comparator(_array[child] , _array[child + 1])){child++;}if (comparator(_array[parent] , _array[child])){std::swap(_array[parent], _array[child]);parent = child;child = 2 * parent + 1;}else{break;}}}

5.priority_queue类模板

namespace Mypriority_queue
{//用仿函数来实现比较器,用于控制堆的类型//用于建大堆的比较函数template<class DataType>class less{public:bool operator()(const DataType& data1, const DataType& data2) const{return data1 < data2;}};//用于建小堆的比较函数template<class DataType>class greater{public:bool operator()(const DataType& data1, const DataType& data2) const{return data1 > data2;}};template<class DataType, class Container = std::vector<DataType>, class Compare = less<DataType>>class priority_queue{public:// 创造空的优先级队列priority_queue() {};//用迭代器区间建堆,采用元素向下调整法建堆template<class Iterator>priority_queue(Iterator first, Iterator last){//将元素都尾插到数组中for (auto it = first; it != last; ++it){_array.push_back(*it);}//采用向下调整建堆,建堆时间复杂度为O(N);for (int tail = (size() - 1 - 1) / 2; tail >= 0; --tail){AdjustDown(tail);}}//堆插入接口void push(const DataType& data){//先将元素尾插到容器中,再执行元素向上调整_array.push_back(data);AdjustUP(size() - 1);}//堆顶元素出队接口void pop(){assert(!empty());//先将堆顶元素交换到堆尾,然后将堆尾元素移除,最后将堆顶元素向下调整恢复堆的结构std::swap(_array.front(), _array.back());_array.pop_back();AdjustDown(0);}//返回队列元素个数的接口size_t size()const{return _array.size();}//队列判空接口bool empty()const{return 0 == size();}// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性const DataType& top()const{assert(!empty());return _array.front();}private://元素向上调整接口void AdjustUP(int child){Compare comparator;int parent = (child - 1) / 2;while (child > 0){if (comparator(_array[parent] , _array[child])){std::swap(_array[child], _array[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}//元素向下调整接口void AdjustDown(int parent){Compare comparator;//先取左孩子int child = 2 * parent + 1;while (child < size()){//取出左右孩子的较大值if (child + 1 < size() && comparator(_array[child] , _array[child + 1])){child++;}if (comparator(_array[parent] , _array[child])){std::swap(_array[parent], _array[child]);parent = child;child = 2 * parent + 1;}else{break;}}}private://储存堆的物理容器Container _array;};
}
  • 值得注意的是利用迭代器区间建堆的构造函数采用的建堆方式是向下调整建堆法,其时间复杂度为O(N),在众多算法实现中这是一个非常常用的建堆接口,关于堆的数据结构理论分析参见:堆的实现与建堆时间复杂度分析
    在这里插入图片描述

http://www.ppmy.cn/news/106695.html

相关文章

深度学习之自编码器实现——实现图像去噪

大家好&#xff0c;我是带我去滑雪&#xff01; 自编码器是一种无监督学习的神经网络&#xff0c;是一种数据压缩算法&#xff0c;主要用于数据降维和特征提取。它的基本思想是将输入数据经过一个编码器映射到隐藏层&#xff0c;再通过一个解码器映射到输出层&#xff0c;使得输…

ESP32设备驱动-TMP006 红外热电堆传感器驱动

TMP006 红外热电堆传感器驱动 文章目录 TMP006 红外热电堆传感器驱动1、TMP006介绍2、硬件准备3、软件准备4、驱动实现1、TMP006介绍 Texas Instruments 的 TMP006 是一系列温度传感器中的第一款,无需接触物体即可测量物体的温度。 它使用非常灵敏的热电堆来测量从物体表面发…

对不起,我们不招还在用Excel的人,和金山系新秀比起差太远了

相信点进来的朋友曾经也深受Excel荼毒。 的确&#xff0c;现如今在网上随便一搜&#xff0c;关于Excel的学习资料和答疑解惑的帖子不胜枚举&#xff0c;盖因为Excel有时太过热心&#xff0c;当然&#xff0c;是帮倒忙的那种热心。 自动把天数转换为日期&#xff0c;还替你把身…

Concepts基本概念

基本概念 本章主要介绍Backtrader独有的基本概念,理解这些概念有利于理解平台的使用。 数据源(data feed) 数据源是Backtrader中最基本的概念,它是一个数据流,回测必须有它。你可以简单把它理解为股票、基金、期货的数据,它可以是来自csv文件、数据库、在线资源或者是…

Spring Boot拦截器与过滤器的区别

Spring Boot拦截器与过滤器的区别 在使用Spring Boot开发Web应用程序时&#xff0c;您可能需要在处理请求之前或之后执行某些操作。这些操作可以包括身份验证、日志记录、性能监测等。在这种情况下&#xff0c;您可以使用两种不同的机制&#xff1a;拦截器和过滤器。本文将介绍…

Oracle面试题

1. 什么是存储过程&#xff0c;使用存储过程的好处&#xff1f; 存储过程&#xff08;Stored Procedure &#xff09;是一组为了完成特定功能的SQL 语句集&#xff0c;经编译后存储在数据库中。用户通过指定存储过程的名字并给出参数&#xff08;如果该存储过程带有参数&#…

IMX6ULL裸机篇之IIC协议

一. IIC实验简介 I2C 是最常用的通信接口&#xff0c;众多的传感器都会提供 I2C 接口来和主控相连。 比如摄像头、 加速度计、触摸屏等。 I.MX6U-ALPHA开发板 使用 I2C1 接口连接了一个距离传感器 AP3216C &#xff0c;本章我们就来学习如何使用 I.MX6U 的 I2C 接口…

WorldCoin : 很多人已经开始免费领币了, 能领1辈子!

来源&#xff1a;彭楠的创业故事 - BV18k4y1x7wt 之前已经介绍过很多次WorldCoin这个项目了&#xff0c;现在全世界已经有越来越多的人&#xff0c;通过了WorldCoin的认证&#xff0c;开始每周免费领代币了&#xff0c;只要认证通过代币就可以领一辈子&#xff0c;非常爽了&…