优先级队列——priority_queue

1、什么是优先级队列?
          顾名思义就是带有优先级的队列,既然是队列,就只能再一端插入,在另一端提取元素,优先级体现在,随便插入元素,他
会自动按照大或者这小的顺序进行排序。
2、用什么结构来实现它呢?       

        如果我们用普通的数组,那么入队时很简单直接随便放入数组,只需要O(1)的时间,然而在出队时要挑选最大的那个优先级,则需要O(n)的时间。同样如果是有序的数组,入队时需要维护这个数组的有序性,找到此优先级合适的位置,需要O(n) 的时间,出队就很简单只需要拿出数组第一个就好了。而如果使用堆的话,则可以非常好的平衡入队与出队的时间复杂度。 使用堆可以将入队与出队的时间复杂度都变成lg(n)级别,虽然使用堆在入队上是慢于普通数组,在出队上是慢于有序数组的,可是平均来讲,使用堆来实现优先队列的时间复杂度大大低于我们使用数组来实现。

//仿函数(函数对象)重载operator()
template <class T>
class Less {
public:
	bool operator()(const T& l, const T& r) {
		return l < r;
	}
};
template<class T>
class Greater {
public:
	bool operator()(const T& l, const T& r) {
		return l > r;
	}
};
template <class T, class Contain = vector<T>, class Compare = Less<T> >
class PriorityQueue {
public :
	Compare com;
	void AdjustUp(size_t child)
	{
                //计算父节点位置
		size_t parent = (child - 1) / 2;
		while (child > 0) {
                        //com.operator()(_con[child], _con[parent]) 
                        //仿函数里面其实就是重载了operator(),但要注意如果容器中放的是自定义
                        //类型的数据,必须重载operator> 和 operator < 
                        //com其实就表示某种优先级,比如说我们现在要按降序进行排列那么下面的
                        //表达式就转化为 if(_con[child] > _con[parent])
			if (com(_con[child] , _con[parent])) {
                                //交换这个节点和它的父节点
				swap(_con[child], _con[parent]);
                                //继续上调
				child = parent;
				parent = (child - 1) / 2;
			}
			else
                                //满足堆性质,直接break
				break;
		}
	}
        
	void AdjustDown(size_t parent)
	{
                //计算左孩子的位置
		size_t child = parent * 2 + 1;
		while (child < _con.size()) {
                        //com和上面一样是某种优先级,假如还是降序输出,我们首先要找出左右孩子
                        //中较大的那一个,然后和parent进行比较(前提是右孩子存在)
		        if ((child + 1 < _con.size()) && 
                             com(_con[child + 1],_con[child])) {
				++child;
			}
                        //如果左右孩子中较大的那个孩子比parent大,交换,然后向下调整
			if (com(_con[child],_con[parent])) {
				swap(_con[parent], _con[child]);
				parent = child;
				child = parent * 2 + 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);
	}
	size_t Size()
	{
		return _con.size();
	}
	bool Empty()
	{
		return _con.empty();
	}
	//返回const是因为堆的元素不能随便修改,否则不满足性质
	const T& Top()
	{
		return _con[0];
	}
private:
	Contain _con;

};

void TestPriorityQueue()
{
	PriorityQueue<int, vector<int>, Greater<int>> p;
	p.Push(4);
	p.Push(9);
	p.Push(32);
	p.Push(67);
	p.Push(54);
	p.Push(5);

	while (!p.Empty()) {
		cout << p.Top() << " ";
		p.Pop();
	}
	cout << endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值