STL(五) priority_queue 基本用法 + 模拟实现

目录

基本用法

模拟实现


前置知识:

数据结构(七) 堆

STL(三) list基本用法 - 仿函数

STL(四) stack 与 queue 基本用法 + 模拟实现 - 容器适配器

基本用法

priority_queue 也是容器适配器,底层容器默认使用 vector,也可以使用 deque,不能使用 list,因为堆的实现需要通过索引计算父亲/孩子下标,list 不满足索引随机访问的特性!

cpp 复制代码
#include <iostream>
#include <queue> //使用 priority_queue 包含的是 queue 头文件
#include <vector>
#include <deque>
using namespace std;
int main()
{
	priority_queue<int> heap; //默认是大堆
	//priority_queue<int, vector<int>> heap; //默认是大堆
	//priority_queue<int, deque<int>> heap; //默认是大堆
	heap.push(6);
	heap.push(2);
	heap.push(8);
	heap.push(4);
	heap.push(1);
	heap.push(5);
	while (heap.size())
	{
		cout << heap.top() << " "; //8 6 5 4 2 1
		heap.pop();
	}
	return 0;
}

priority_queue 默认是大堆,那如果我们要用小堆,该怎么创建?我们只需要再给容器的第三个模版参数传递一个仿函数即可!

cpp 复制代码
template 
<
    class T,                // 存储的元素类型
    class Container = vector<T>,  // 底层容器(默认 vector)
    class Compare = less<typename Container::value_type>  // 比较规则(默认大根堆)
> class priority_queue;
cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main()
{
	//priority_queue<int, vector<int>, less<int>> heap; //大堆
	priority_queue<int, vector<int>, greater<int>> heap; //小堆
	heap.push(6);
	heap.push(2);
	heap.push(8);
	heap.push(4);
	heap.push(1);
	heap.push(5);
	while (heap.size())
	{
		cout << heap.top() << " "; //1 2 4 5 6 8
		heap.pop();
	}
	return 0;
}

下面我们看看 priority_queue 存放自定义类型:

如果我们依旧传递 标准库提供的 less 仿函数,less仿函数在内部会比较 a < b,由于存储的是自定义类型数据,因此我们要在自定义类里对 < 进行重载!

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

class person
{
public:
	string _name;
	int _age;
	
	person(string name, int age)
		:_name(name)
		,_age(age)
	{}

	bool operator<(const person& p) const
	{
		return _age < p._age;
	}
};

int main()
{
	priority_queue<person, vector<person>, less<person>> heap; //大堆
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄降序排列
		heap.pop();
	}
	return 0;
}

同理,如果我们依旧传递 标准库提供的 greater 仿函数,less仿函数在内部会比较 a > b,由于存储的是自定义类型数据,因此我们要在自定义类里对 > 进行重载!

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

class person
{
public:
	string _name;
	int _age;
	
	person(string name, int age)
		:_name(name)
		,_age(age)
	{}

	bool operator>(const person& p) const
	{
		return _age > p._age;
	}
};

int main()
{
	priority_queue<person, vector<person>, greater<person>> heap; //小堆
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄升序排列
		heap.pop();
	}
	return 0;
}

如果不想使用 标准库 提供的 less / greater 仿函数,我们也可以自己定义仿函数

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

class person
{
public:
	string _name;
	int _age;
	
	person(string name, int age)
		:_name(name)
		,_age(age)
	{}
};

class compare
{
public:
	bool operator()(const person& p1, const person& p2)
	{
		return p1._age < p2._age; //大堆
	}
};

int main()
{
	priority_queue<person, vector<person>, compare> heap;
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄降序排列
		heap.pop();
	}
	return 0;
}
cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

class person
{
public:
	string _name;
	int _age;
	
	person(string name, int age)
		:_name(name)
		,_age(age)
	{}
};

class compare
{
public:
	bool operator()(const person& p1, const person& p2)
	{
		return p1._age > p2._age; //小堆
	}
};

int main()
{
	priority_queue<person, vector<person>, compare> heap;
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄升序排列
		heap.pop();
	}
	return 0;
}

模拟实现

前面关于容器适配器和仿函数的知识已经铺垫的很到位了,我们直接实现一个完整的 priority_queue,可以指定底层容器,可以传递仿函数控制大小堆~

cpp 复制代码
#include<iostream>
#include<vector>
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 dck
{
	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)
			:_con(first, last)
		{
			//建堆
			for (int i = (_con.size() - 2) / 2; i > 0; i--)
			{
				adjust_down(i);
			}
		}

		void adjust_up(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (com.operator()(_con[parent], _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void adjust_down(int parent)
		{
			Compare com;
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					++child;
				}
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

		const T& top()
		{
			return _con[0];
		}

		bool empty()
		{
			return _con.empty();
		}

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

测试:

cpp 复制代码
void test1()
{
	//dck::priority_queue<int, vector<int>, Less<int>> heap; //大堆
	dck::priority_queue<int, vector<int>, Greater<int>> heap; //小堆
	heap.push(6);
	heap.push(2);
	heap.push(8);
	heap.push(4);
	heap.push(1);
	heap.push(5);
	while (heap.size())
	{
		cout << heap.top() << " "; //1 2 4 5 6 8
		heap.pop();
	}
}


class person
{
public:
	string _name;
	int _age;

	person(string name, int age)
		:_name(name)
		, _age(age)
	{}

	//bool operator<(const person& p) const
	//{
	//	return _age < p._age;
	//}

	bool operator>(const person& p) const
	{
		return _age > p._age;
	}
};

void test2()
{
	//dck::priority_queue<person, vector<person>, Less<person>> heap; //大堆
	dck::priority_queue<person, vector<person>, Greater<person>> heap; //小堆
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄升序排列
		heap.pop();
	}
}

class compare
{
public:
	//bool operator()(const person& p1, const person& p2)
	//{
	//	return p1._age < p2._age; //大堆
	//}

	bool operator()(const person& p1, const person& p2)
	{
		return p1._age > p2._age; //小堆
	}
};

void test3()
{
	dck::priority_queue<person, vector<person>, compare> heap;
	heap.push(person("张三", 20));
	heap.push(person("李四", 15));
	heap.push(person("王五", 22));
	heap.push(person("二蛋", 19));
	while (heap.size())
	{
		cout << heap.top()._name << " " << heap.top()._age << endl; //按照年龄升序排列
		heap.pop();
	}
}

int main()
{
	test1();
	test2();
	test3();
	return 0;
}
相关推荐
一念一花一世界1 小时前
Arbess从初级到进阶(9) - 使用Arbess+GitLab实现C++项目自动化部署
c++·ci/cd·gitlab·arbess
大锦终1 小时前
【Linux】Reactor
linux·运维·服务器·c++
沐怡旸2 小时前
【穿越Effective C++】23.宁以non-member、non-friend替换member函数
c++·面试
青小俊2 小时前
【代码随想录c++刷题】-二分查找 移除元素 有序数组的平方 - 第一章 数组 part 01
c++·算法·leetcode
赖small强3 小时前
【Linux C/C++开发】第16章:多线程编程基础
linux·c语言·c++·多线程编程·进程和线程的本质区别
AA陈超3 小时前
以 Lyra 的架构为基础,创建一个名为 “Aura“ 的英雄并实现发射火球技能
c++·笔记·学习·ue5·lyra
xlq223224 小时前
16.17.list(上)
c++·list
cpp_25015 小时前
P1765 手机
数据结构·c++·算法·题解·洛谷
未到结局,焉知生死5 小时前
PAT每日三题11-20
c++·算法