priority_queue的简单模拟实现

priority_queue
1.priirity_queue优先级队列是一种容器适配器。
2.priority_queue底层的数据结构是vector,通过堆算法来来排序从而实现优先级队列
3.默认情况下,priority_queue是大堆(降序)
模拟实现代码如下:

//PriorityQueue.h
#pragma once
#include
namespace yqx
{
	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;
		}
	};
	template<class T, class Container = vector<T>,class Compar = Less<T>>
	class priority_queue
	{
	public:
		
		priority_queue()
		{

		}
		template <class InputIterator>//迭代器范围初始化
		priority_queue(InputIterator first, InputIterator last)
		{
			//将数据插入
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}
			//建堆
			for (int i = (_con.size() - 2) / 2; i >= 0; --i)
			{
				AdjustDown(i);
			}	
		}
		size_t size()const
		{
			return _con.size();
		}

		void Adjustup(size_t child)  
		{
			Compar com;//仿函数定义对象
			size_t parent = (child - 1) / 2;
			while (child > 0)
			{
				if (com(_con[parent],_con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
					break;
			}
		}

		void AdjustDown(size_t parent)
		{
			Compar com;//仿函数定义对象
			size_t child = 2 * parent + 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[parent], _con[child]);
					parent = child;
					child = 2 * parent + 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);
		}

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

		bool empty()
		{
			return _con.empty();
		 }
	private:
		Container _con;
	};
}










//Test.cpp(测试用例)
#include
using namespace std;
#include
#include
#include
#include"PriorityQueue.h"




//使用库函数中的priority_queue
//int main()
//{
//	priority_queue, less> lt;
//	lt.push(2);
//	lt.push(1);
//	lt.push(3);
//	lt.push(5);
//	lt.push(4);
//	while (!lt.empty())
//	{
//		cout << lt.top() << " ";
//		lt.pop();
//	}
//	cout << endl;
//	return 0;
//}


//打印容器中的元素
//tpyename的使用会在代码块下边做以简单介绍
template<class Container>
void PrintContainer(const Container& p)
{
	 typename Container::const_iterator it = p.begin();
	while (it != p.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}


class Date
{
public:

	Date(int year = 1990,int month = 1 ,int day =1)
		:_year(year)
		,_month(month)
		,_day(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);
	}
	friend ostream& operator<<(ostream& out, const Date& d);
	friend class PDateLess;
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d)//日期类输出重载
{
	cout << d._year << "-" << d._month << "-" << d._day;
	return out;
 }

class PDateLess
{
public:
	
	bool operator()(const Date* p1, const Date* p2)const
	{
	/*	return (p1->_year < p2->_year) ||
			(p1->_year == p2->_year && p1->_month < p2->_month) ||
			(p1->_year == p2->_year && p1->_month == p2->_month && p1->_day < p2->_day);*/
		return *p1 < *p2;
	}
};

int main()
{
	//将类作为priority_queue初始化构造的元素
	/*yqx::priority_queue,DateLess> lt;
	lt.push(Date(2020, 12, 23));
	lt.push(Date(2020, 11, 25));

	lt.push(Date(2020, 12, 24));
	lt.push(Date(2020, 11, 22));
	cout << lt.top() << endl;
	lt.pop();*/





	//使用类的指针来构造priority_queue
	yqx::priority_queue<Date*,vector<Date*>,PDateLess> lt;
	lt.push(new Date(2020, 12, 23));
	lt.push(new Date(2020, 11, 25));
	lt.push(new Date(2020, 12, 24));
	lt.push(new Date(2020, 11, 22));
	cout << *lt.top() << endl;
	lt.pop();




	/*yqx::priority_queue> lt;
	lt.push(2);
	lt.push(1);
	lt.push(3);
	lt.push(5);
	lt.push(4);
	while (!lt.empty())
	{
		cout << lt.top() << " ";
		lt.pop();
	}
	cout << endl;

	//C++11中初始化构造容器的新方法
	vector l = { 1,2,5,7,6,10,8 };
	
	//打印某个容器中的元素
	PrintContainer(l);



	//使用某个容器的迭代器范围来初始化构造priority_queue
	yqx::priority_queue, greater> llt(l.begin(),l.end());
	while (!llt.empty())
	{
		cout << llt.top() << " ";
		llt.pop();
	}
	cout << endl;*/
	return 0;
}

关键字typename的使用

//typename的使用
template<class Container>
void PrintContainer(const Container& p)
{
	  Container::const_iterator it = p.begin();
	while (it != p.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

priority_queue的简单模拟实现_第1张图片
对于用于模板定义的依赖于模板参数的名称,只有在实例化的参数中存在这个类型名,或者这个名称前使用了 typename 关键字来修饰,编译器才会将该名称当成是类型。除了以上这两种情况,绝不会被当成是类型。

因此,如果你想直接告诉编译器 T::const_iterator 是类型而不是变量,只需用 typename修饰:

	typename    Container::const_iterator it = p.begin();
	typename    Container::const_iterator it (p.begin());

加上typename之后,编译器就会知道这是个类型,而不再需要等到实例化时期才能确定。

初识仿函数
仿函数(Functor)又称为函数对象(Function Object)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()运算符。因为调用仿函数,实际上就是通过类对象调用重载后的operator()运算符。
如果要将某种“操作”当做算法的参数,一般有两种方法:
(1)先将该“操作”设计为一个函数,再将函数指针当做算法的一个参数。
(2)将该“操作”设计为一个仿函数(就语言层面而言是个class),再以该仿函数产生一个对象,并以此对象作为算法的一个参数。

很明显第二种方法会更优秀,在我们写代码时有时会发现有些功能代码,会不断地被使用。为了复用这些代码,实现为一个公共的函数是一个解决方法。不过函数用到的一些变量,可能是公共的全局变量。引入全局变量,容易出现同名冲突,不方便维护。
priority_queue的简单模拟实现_第2张图片

仿函数的优点:

仿函数是模板函数,.在同一时间里,由某个仿函数所代表的单一函数,可能有不同的状态,可以根据不同的类型代表不同的状态
仿函数是模板函数,所以仿函数即使定义相同,也可能有不同的类型
仿函数是模板函数,仿函数通常比一般函数速度慢
仿函数使程序代码变简单,仿函数在一定程度上使代码更通用,本质上简化了代码

你可能感兴趣的:(c++)