C++----剖析priority_queue,仿函数的使用

priority_queue与queue有哪些不同之处呢?引入了优先级,与普通队列(先进先出,FIFO)不同,优先级队列会根据元素的优先级来决定元素的出队顺序。优先级高的元素会优先出队,而优先级低的元素则需要等待。那么它是用什么来作为底层容器的呢?要能够适配优先级,那就要使用到堆,那使用vector连续地址的容器会方便一些。用来存储堆,模拟堆的动作。首先优先级队列默认是less函数,也就是大堆,优先级高的在前面,先出,所以先实现大堆,这里要控制一下<>号的使用,统一一下,大堆用<。

	 //优先级队列 默认是大堆,是<   小堆是>
	template<class T, class container=std::vector<T>>
	class priority_queue
	{
		void Adjustup(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)//不能是parent>=0
			{
				if (c[parent]< c[child])
				{
					std::swap(c[child], c[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			Compare com;
			while (child<c.size())//父亲为叶节点 孩子超出数组了
			{
				if (child + 1 < c.size() and c[child] < c[child + 1])
				{
					child += 1;
				}
				if (c[parent]< c[child])
				{
					std::swap(c[child], c[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}

	public:
		void push(const T& x)
		{
			c.push_back(x);

			Adjustup(c.size() - 1);
		}

		void pop()
		{
			assert(!c.empty());
			std::swap(c[0], c[c.size() - 1]);
			//用的是vector,vector没有头删,所以首尾要交换一下
			c.pop_back();

			AdjustDown(0);
		}

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

		size_t size()
		{
			return c.size();
		}

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

	private:
		container c;
	};

先大概实现了大堆时的情况,我们知道肯定会有小堆的情况,总不能再写一个prority吧?怎么办?类似前面的迭代器,在模板参数上做文章,这里就引入了仿函数!仿函数顾名思义,模拟函数,但不是函数,而是使用类和对象重载函数,让对象调用成员函数看上去像函数:

	//仿函数
	template<class T>
	struct less
	{
		bool operator()(const T& a, const T& b) const
		{
			return a < b;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& a, const T& b) const
		{
			return a > b;
		}
	};

此时,我们在刚刚的priority中加入函数类型不就ok了?

	 //优先级队列 默认是大堆,是<   小堆是>
	template<class T, class Compare = less<T>, class container=std::vector<T>>
	class priority_queue
	{
		void Adjustup(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)//不能是parent>=0
			{
				//if (c[parent]< c[child])
				if (com(c[parent] , c[child]))
				{
					std::swap(c[child], c[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void AdjustDown(int parent)
		{
			int child = parent * 2 + 1;
			Compare com;
			while (child<c.size())//父亲为叶节点 孩子超出数组了
			{
				//if (child + 1 < c.size() and c[child] < c[child + 1])
				if (child + 1 < c.size() and com(c[child], c[child + 1]))

				{
					child += 1;
				}
				//if (c[parent]< c[child])
				if (com(c[parent], c[child]))
				{
					std::swap(c[child], c[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					break;
			}
		}
        //..........

在使用模板参数时,它可以接收任何类型参数,不必太关心class后面的名称,与名称无关!名称只是为了方便我们使用而已,传过去是什么就是什么。比如传greater<T>时,其实就是传过去了类类型,与vector<T>是一样的

使用:

void test3()
{
	//w::priority_queue<int> s;

	w::priority_queue<int, w::greater<int>> s;


	s.push(7);
	std::cout << s.top() << std::endl;
	s.push(4);
	std::cout << s.top() << std::endl;
	s.push(8);
	std::cout << s.top() << std::endl;
	s.push(1);
	std::cout << s.top() << std::endl;
	s.pop();
	std::cout << s.top() << std::endl;;
	s.pop();
	std::cout << s.top() << std::endl;;
	s.pop();
	std::cout << s.top() << std::endl;;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_w_z_j_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值