【C++】STL之priority_queue类源码剖析

目录

概述

算法

源码

PriorityQueue.h

test.cpp

测试结果


概述

priority_queue:优先级队列,包含在头文件<queue>中

优先级队列类似于堆结构,优先级最高的元素被置为堆顶,最优先被弹出top()和删除pop()

优先级队列的默认调整策略是大根堆,也就是最大值在堆顶

自定义类型需要用户自己提供 "<" 和 ">" 的重载才能使用优先级队列

元素的每一次插入push(),都是擦在队尾,再从队尾进行一次向上调整adjust_up()

元素的每一次删除pop(),都是删除堆顶元素(先将堆顶元素与末尾元素交换,再尾删),最后再从堆顶进行向下调整adjust_down()

算法

priority_queue优先级队列的设计,成员变量默认为一个vector容器变量,调整策略默认为less,这样大大简化了代码。

priority_queue优先级队列采用堆结构的设计方案,有其独特的特性,但每次插入删除都会进行调整,这样牺牲了部分性能。

用优先级队列调整自定义类型,需要自己提供 "<" 和 ">" 的重载

源码

PriorityQueue.h

#pragma once

#include <iostream>
#include <vector>

template<class T>
class Less
{
public:
	bool operator()(const T& x, const T& y)const
	{
		return x < y;
	}
};

template<class T>
class Greater
{
public:
	bool operator()(const T& x, const T& y)const
	{
		return x > y;
	}
};

// 默认调整策略为 less,parent比child小则调整,建大根堆
template<class T,class Container = std::vector<T>, class Compare = Less<T>>
class PriorityQueue
{
public:
	PriorityQueue()
	{}

	template<class InputIterator>
	PriorityQueue(InputIterator first, InputIterator last)
		: _con(first, last)
	{
		for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; --i)
		{
			adjust_down(i);
		}
	}

	void adjust_up(size_t child)
	{
		Compare com;
		size_t parent = (child - 1) / 2;
		while (child > 0)
		{
			if (com(_con[parent], _con[child]))
			{
				std::swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}
	void adjust_down(size_t parent)
	{
		Compare com;
		size_t 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]))
			{
				std::swap(_con[child], _con[parent]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}

	void push(const T& x)
	{
		_con.push_back(x);
		adjust_up(_con.size() - 1);
	}
	void pop()
	{
		std::swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		adjust_down(0);
	}

	const T& top()const
	{
		return _con[0];
	}
	bool empty()const
	{
		return _con.empty();
	}
	size_t size()const
	{
		return _con.size();
	}

private:
	Container _con;
};

test.cpp

#include "PriorityQueue.h"
#include <iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year), _month(month), _day(day)
	{}

	bool operator==(const Date& d)const
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}
	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator>(const Date& d)const
	{
		return !(*this < d || *this == d);
	}

	friend ostream& operator<<(ostream& os, const Date& d)
	{
		os << d._year << "-" << d._month << "-" << d._day;
		return os;
	}

private:
	int _year, _month, _day;
};

struct PDateLess
{
	bool operator()(const Date* d1, const Date* d2)
	{
		return *d1 < *d2;
	}
};

struct PDateGreater
{
	bool operator()(const Date* d1, const Date* d2)
	{
		return *d1 > *d2;
	}
};

void Test()
{
	// 大堆,需要用户在自定义类型中提供 < 的重载
	PriorityQueue<Date> q1;
	q1.push(Date(2018, 10, 1));
	q1.push(Date(2019, 5, 20));
	q1.push(Date(2020, 2, 14));
	cout <<"q1.top = " << q1.top() << endl;
	while (q1.size())
	{
		cout << q1.top() << endl;
		q1.pop();
	}
	cout << endl;

	// 小堆,需要用户在自定义类型中提供 > 的重载
	PriorityQueue<Date, vector<Date>, greater<Date>> q2;
	q2.push(Date(2018, 10, 1));
	q2.push(Date(2019, 5, 20));
	q2.push(Date(2020, 2, 14));
	cout << "q2.top = " << q2.top() << endl;
	while (q2.size())
	{
		cout << q2.top() << endl;
		q2.pop();
	}
	cout << endl;

	PriorityQueue<Date*, vector<Date*>, PDateLess> q3;
	q3.push(new Date(2018, 10, 1));
	q3.push(new Date(2019, 5, 20));
	q3.push(new Date(2020, 2, 14));
	cout << "q3.top = " << *q3.top() << endl;
	while (q3.size())
	{
		cout << *q3.top() << endl;
		q3.pop();
	}
	cout << endl;

	PriorityQueue<Date*, vector<Date*>, PDateGreater> q4;
	q4.push(new Date(2018, 10, 1));
	q4.push(new Date(2019, 5, 20));
	q4.push(new Date(2020, 2, 14));
	cout << "q4.top = " << *q4.top() << endl;
	while (q4.size())
	{
		cout << *q4.top() << endl;
		q4.pop();
	}
	cout << endl;
}

int main()
{
	Test();

	return 0;
}

测试结果

猜你喜欢

转载自blog.csdn.net/phoenixFlyzzz/article/details/130462347