C++ priority_queue的使用与简单实现

目录

[1. priority_queue的介绍](#1. priority_queue的介绍)

[2. 仿函数](#2. 仿函数)

[(1). 概念](#(1). 概念)

[(2). 特点](#(2). 特点)

[3. priority_queue的使用](#3. priority_queue的使用)

[4. priority_queue模拟实现](#4. priority_queue模拟实现)

[(1). 如何插入时构建堆,删除时维持堆](#(1). 如何插入时构建堆,删除时维持堆)

[(2). 成员函数实现具体功能](#(2). 成员函数实现具体功能)

[5. 全部代码](#5. 全部代码)

[(1). priority_queue.h](#(1). priority_queue.h)

[(2). test.cpp](#(2). test.cpp)


1. priority_queue的介绍

  1. 是一种容器适配器

  2. 优先使用vector作为其底层存储数据的容器。

  3. 使用了堆算法将vector中元素构造成堆的结构,所以priority_queue类似于堆,用的到堆的地方都可以考虑使用priority_queue。

  4. 默认 情况下priority_queue建立的是大堆

  5. 使用时只需包含#include<queue>即可

其底层容器需要支持随机访问迭代器(Random-access iterators)以便自身在内部始终保持堆结构。这些由容器适配器自动完成,通过自动调用算法函数make_heap、push_heap、pop_heap,完成操作

priority_queue的模板参数有三个

上图中的

  1. T为存储的数据类型

  2. Container为存储数据的底层容器

  3. Compare为仿函数

2. 仿函数

(1). 概念

就是模仿函数的对象,它们可以通过重载operator() 来使得对象可以像函数一样被调用,即可以使用圆括号()来传递参数,返回结果

(2). 特点
  1. 通过重载operator(),仿函数对象可接收参数并返回结果,看起来类似于普通的函数

  2. 与普通函数不同,仿函数作为对象,可以拥有成员变量。这意味着它更加灵活

  3. 与模板结合提供类型安全的泛型编程。算法接收仿函数作为参数,已实现算法的灵活性

使用如下所示

cpp 复制代码
#include<algorithm>  
#include<vector>  
#include<iostream>  


int main()
    {
    std::vector<int> vec = { 3, 1, 4, 1, 5, 9, 2 };

    sort(vec.begin(), vec.end());
    for (int n : vec)//auto也可以
    {
        std::cout << n << ' ';
    }
    std::cout << std::endl;
    // 使用 greater 对 vec 进行降序排序  
    sort(vec.begin(), vec.end(), std::greater<int>());
    for (int n : vec)
    {
        std::cout << n << ' ';
    }
    std::cout << std::endl;

    return 0;
}

以上代码中的greater就是仿函数(模板函数对象)通常用来比较大于,与之相对的less用来比较小于,我们上面传参数相当于传了个匿名对象

3. priority_queue的使用

|---------------------------------------------|-----------------------------|
| 函数声明 | 接口说明 |
| priority_queue()/priority_queue(first,last) | 构造一个空的优先级队列/根据迭代器(左开右闭)构造空间 |
| empty() | 检测优先级队列是否为空 |
| top() | 返回优先级队列中最大(最小元素),即堆顶元素 |
| push(x) | 在优先级队列中插入元素x |
| pop() | 删除优先级队列中最大(最小)元素,即为堆顶元素 |

代码如下所示

cpp 复制代码
#include<algorithm>  
#include<vector>  
#include<iostream>
#include<queue>
using namespace std;
int main() 
{
    vector<int> v{ 1,6,5,9,8,7,3,4 };
    priority_queue<int> pq1;
    priority_queue<int, vector<int>, greater<int>> pq2(v.begin(), v.end());
    for (auto vv : v)
    {
        pq1.push(vv);
    }
    //默认创建的是大堆,由下输出可得
    while(!pq1.empty())
    {
        cout << pq1.top() << " ";
        pq1.pop();
    }
    cout << endl;
    //可以通过greater<int>来创建小堆
    while (!pq2.empty())
    {
        cout << pq2.top() << " ";
        pq2.pop();
    }

    return 0;
}

输出结果如下

如果利用我们自己写的仿函数呢?

cpp 复制代码
#include<algorithm>  
#include<vector>  
#include<iostream>
#include<queue>
using namespace std;
template <class T>
class greaternum
{
public:
    bool operator()(T a, T b)
    {
        return a > b;
    }

};
int main() 
{
    vector<int> v{ 1,6,5,9,8,7,3,4 };
    priority_queue<int> pq1;
    priority_queue<int, vector<int>, greaternum<int>> pq2(v.begin(), v.end());
    for (auto vv : v)
    {
        pq1.push(vv);
    }
    //默认创建的是大堆,由下输出可得
    while(!pq1.empty())
    {
        cout << pq1.top() << " ";
        pq1.pop();
    }
    cout << endl;
    //可以通过greater<int>来创建小堆
    while (!pq2.empty())
    {
        cout << pq2.top() << " ";
        pq2.pop();
    }

    return 0;
}

运行结果依然为

4. priority_queue模拟实现

(1). 如何插入时构建堆,删除时维持堆

这里我们就需要使用向上调整算法和向下调整算法了

cpp 复制代码
namespace Pc
{
	template<class T,class container=vector<T>,class compare=greater<T>>
	class priority_queue
	{
	public:
		void AdjustUp(int child)
		{
			compare adjust;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if(con[child]> con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child] ,con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}
		void AdjustDown(int head)
		{
			compare adjust;
			int parent = head;
			int child = parent * 2 + 1;
			int n = con.size();
			while (child < con.size())
			{
				//if (con.size()<child + 1 && con[child + 1]< con[child])
				if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
				{
					child ++;
				}
				//if (con[child]< con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = child * 2 + 1;
				}
				else
					break;
			}
		}
	private:
		container con;
	};
}

这里应用了仿函数,实现如下

cpp 复制代码
template <class T>
class lessnum
{
public:
	bool operator()( T a,T b)
	{
		return a < b;
	}

};
template <class T>
class greaternum
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}

};

比起用C语言实现堆少了一些参数,具体思路并没发生改变

(2). 成员函数实现具体功能

插入,删除,返回堆顶元素,判空,返回队列里元素个数

cpp 复制代码
		void push(const T& x)
		{
			con.push_back(x);
			AdjustUp(con.size()-1);

		}
		void pop()
		{
			swap(con[0], con[con.size()-1]);
			con.pop_back();
			AdjustDown(0);
		}
		T& top()
		{
			return con.back();
		}
		const T& top() const
		{
			return con.back();
		}
		bool empty()
		{
			return con.empty();
		}
		size_t size()
		{
			return con.size();
		}
		//void print()//用来方便观测优先级队列
		//{
			//for (int i = 0; i < size(); i++)
		//	{
		//		cout << con[i] << "   ";
		//	}
		//	cout << endl;
		}

5. 全部代码

(1). priority_queue.h
cpp 复制代码
namespace Pc
{
	template<class T,class container=vector<T>,class compare=greater<T>>
	class priority_queue
	{
	public:
		priority_queue() {}

		void AdjustUp(int child)
		{
			compare adjust;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if(con[child]> con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child] ,con[parent]);
					child = parent;
					parent = (parent - 1) / 2;
				}
				else
					break;
			}
		}
		void AdjustDown(int head)
		{
			compare adjust;
			int parent = head;
			int child = parent * 2 + 1;
			int n = con.size();
			while (child < con.size())
			{
				//if (con.size()<child + 1 && con[child + 1]< con[child])
				if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
				{
					child ++;
				}
				//if (con[child]< con[parent])
				if (adjust(con[child] , con[parent]))
				{
					swap(con[child], con[parent]);
					parent = child;
					child = child * 2 + 1;
				}
				else
					break;
			}
		}
		void push(const T& x)
		{
			con.push_back(x);
			AdjustUp(con.size()-1);

		}
		void pop()
		{
			swap(con[0], con[con.size()-1]);
			con.pop_back();
			AdjustDown(0);
		}
		T& top()
		{
			return con.back();
		}
		const T& top() const
		{
			return con.back();
		}
		bool empty()
		{
			return con.empty();
		}
		size_t size()
		{
			return con.size();
		}
		void print()
		{
			for (int i = 0; i < size(); i++)
			{
				cout << con[i] << "   ";
			}
			cout << endl;
		}
	private:
		container con;
	};
}
(2). test.cpp

priority_queue.h中的代码在以下代码#include"priority_queue.h" 处展开

cpp 复制代码
#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;

#include"priority_queue.h"
template <class T>
class lessnum
{
public:
	bool operator()( T a,T b)
	{
		return a < b;
	}

};
template <class T>
class greaternum
{
public:
	bool operator()(T a, T b)
	{
		return a > b;
	}

};
int main()
{
	//Pc::priority_queue<int, vector<int>, lessnum<int>> pq;
	//Pc::priority_queue<int, vector<int>, greaternum<int>> pq;
	Pc::priority_queue<int, vector<int>> pq;
	pq.push(1);
	pq.push(12);
	pq.push(123);
	pq.push(1234);
	while (!pq.empty())
	{
		pq.print();
		cout << "最后一个元素: " << pq.top() << "   元素还有:"<<pq.size() << endl;
		pq.pop();
	}
	return 0;
}

到此为止了

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

相关推荐
荒古前5 分钟前
龟兔赛跑 PTA
c语言·算法
Colinnian8 分钟前
Codeforces Round 994 (Div. 2)-D题
算法·动态规划
Algorithm15768 分钟前
云原生相关的 Go 语言工程师技术路线(含博客网址导航)
开发语言·云原生·golang
用户00993831430114 分钟前
代码随想录算法训练营第十三天 | 二叉树part01
数据结构·算法
shinelord明18 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
დ旧言~24 分钟前
专题八:背包问题
算法·leetcode·动态规划·推荐算法
Monly2124 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu25 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee202125 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频