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

测试结果

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
神书-STL实现原理,对于强化数据结构-算法的程序员必备、必读书籍。The Best-Selling Programmer Resource–Now Updated for C++11 The C++ standard library provides a set of common classes and interfaces that greatly extend the core C++ language. The library, however, is not self-explanatory. To make full use of its components - and to benefit from their power - you need a resource that does far more than list the classes and their functions. The C++ Standard Library - A Tutorial and Reference, 2nd Edition describes this library as now incorporated into the new ANSI/ISO C++ language standard (C++11). The book provides comprehensive documentation of each library component, including an introduction to its purpose and design; clearly written explanations of complex concepts; the practical programming details needed for effective use; traps and pitfalls; the exact signature and definition of the most important classes and functions; and numerous examples of working code. The book focuses on the Standard Template Library (STL), examining containers, iterators, function objects, and STL algorithms. You will also find detailed coverage of strings, concurrency, random numbers and distributions, special containers, numerical classes, internationalization, and the IOStreams library. An insightful introduction to fundamental concepts and an overview of the library will help bring newcomers quickly up to speed. A comprehensive index will support the C++ programmer in his/her day-to-day life.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AllinTome

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值