优先队列/堆

template <typename T> class MaxQ {
public:
	MaxQ(std::initializer_list<T> il) :_v(il) {}
	
	size_t size() { return _v.size(); }
	void showData() { for_each(_v.begin(), _v.end(), 
						[](const T x) {std::cout << x << " "; }); 
							std::cout << std::endl; }

	void insert(T value);
	T delMax();
private:
	void swim(int k);
	void sink(int k);
	std::vector<T> _v;
};

//往队列中末尾插入元素,并调用swim将其放在合适的位置
template <typename T>
void MaxQ<T>::insert(T value)
{
	_v.push_back(value);
	swim(_v.size() - 1);
}

template <typename T>
void MaxQ<T>::swim(int k)
{
	//k代表的是在数组中的位置
	//因为当k处于二叉堆的第2层,与第一层(即k=1)进行交换,所以这里的循环判断条件为 k > 1
	//当父结点_v[k/2]小于当前处理的结点_v[k]时,k结点往上移
	while (k > 1 && _v[k] > _v[k / 2]) {	
		std::swap(_v[k], _v[k / 2]);		
		k = k / 2;						//跳至二叉堆的上一层
	}
}
//弹出二叉堆中最大的元素,由insert已知最大值存在_v[1]
//将末尾元素提上来填补_v[1]的位置,接着将其下沉到合适的位置,因为堆在数组中的存储并不是有序的
template <typename T>
T MaxQ<T>::delMax()
{
	assert(_v.size() >= 2);
	auto max = _v[1];
	std::swap(_v[1], _v[_v.size() - 1]);
	_v.pop_back();
	sink(1);

	return max;
}
template <typename T>
void MaxQ<T>::sink(int k)
{
	while (2 * k <= _v.size()-1 ) {		//当下沉至>2k位置,表示已经在堆的底层,循环终止
		int j = 2 * k;				
		if (j < _v.size()-1 && _v[j] < _v[j + 1])	//判断两个子结点的大小
			++j;
		if (_v[j] > _v[k])				//判断父结点k和子结点j的大小
			std::swap(_v[j], _v[k]);
		else
			break;						//当父结点大于子结点,循环终止
		k = j;							//向下沉
	}
}


优先队列运用于在接近无限大N的输入中,找出最大(最小)的M个元素。

如果用数组来实现二叉堆的话,那么位置k的结点的父结点的位置为k/2,而它的两个子结点的位置分别为2k和2k+1

数组中A[0]不使用,示例代码中使用最大堆

优先队列能够保证插入元素和删除最大元素这两个操作复杂度为NlogM

猜你喜欢

转载自blog.csdn.net/pierce_liu/article/details/72895997
今日推荐