[C++] STL priority_queue class source code analysis

Table of contents

overview

algorithm

source code

PriorityQueue.h

test.cpp

Test Results


overview

priority_queue: priority queue, included in the header file <queue>

The priority queue is similar to the heap structure. The element with the highest priority is placed on the top of the heap, and the highest priority is popped up by top() and deleted by pop()

The default adjustment strategy of the priority queue is the big root heap, that is, the maximum value is at the top of the heap

User-defined types need to provide overloads of "<" and ">" to use the priority queue

Every time an element is inserted into push(), it is wiped at the end of the queue, and then an upward adjustment is made from the tail of the queue adjust_up()

Every deletion pop() of an element is to delete the top element of the heap (first exchange the top element with the end element, and then delete the end), and finally adjust down from the top of the heap (adjust_down())

algorithm

priority_queue The design of the priority queue, the member variable defaults to a vector container variable, and the adjustment strategy defaults to less, which greatly simplifies the code.

priority_queue The priority queue adopts the design scheme of the heap structure, which has its unique characteristics, but it will be adjusted every time insertion and deletion, which sacrifices part of the performance.

To adjust custom types with priority queues, you need to provide overloads of "<" and ">"

source code

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;
}

Test Results

 

Guess you like

Origin blog.csdn.net/phoenixFlyzzz/article/details/130462347