C++之实现优先队列

二叉堆详解实现优先级队列

二叉堆主要操作有2个:sink(下沉)和 swim(上浮),用以维护二叉堆的性质。
其主要应用有两个,首先是一种排序方法【堆排序】,第二是一种很有用的数据结构【优先级队列】。

二叉堆

首先,二叉堆和二叉树有啥关系呢,为什么人们总数把二叉堆画成一棵二叉树?
因为,二叉堆其实就是一种特殊的二叉树(完全二叉树),只不过存储在数组里。一般的链表二叉树,我们操作节点的指针,而在数组里,我们把数组索引作为指针:

// 父节点的索引
int parent(int root) {
    return root / 2;
}
// 左孩子的索引
int left(int root) {
    return root * 2;
}
// 右孩子的索引
int right(int root) {
    return root * 2 + 1;
}

C++之实现优先队列_第1张图片

把 arr[1] 作为整棵树的根的话,每个节点的父节点和左右孩子的索引都可以通过简单的运算得到,这就是二叉堆设计的一个巧妙之处。
二叉堆还分为最大堆和最小堆。最大堆的性质是:每个节点都大于等于它的两个子节点。类似的,最小堆的性质是:每个节点都小于等于它的子节点。
两种堆核心思路都是一样的,本文以最大堆为例讲解。

2. 优先级队列
  • 优先级队列这种数据结构有一个很有用的功能,你插入或者删除元素的时候,元素会自动排序,这底层的原理就是二叉堆的操作。
  • 数据结构的功能无非增删查该,优先级队列有两个主要 API,分别是 insert 插入一个元素和 delMax 删除最大元素(如果底层用最小堆,那么就是 delMin)。而这两种API都可以通过上沉和下浮实现。
3. 代码实现
#include 
using namespace std;

class PriorityQueue
{
pritvate:
	int* pArray;
	int m_length;
public:
	PriorityQueue(int N){
		// 根节点直接从pArray[1[开始,所以长度要N+1
		pArray = new int[N + 1];
		m_length = 0;
	}
	//上浮
	void swim(int k){	//k为数组的id
		//若叶子节点k所对应的值大于其父节点,上浮
		while(k > 1 && pArray[k] > pArray[k/2]){
			swap(pArray[k], pArray[k/2]);	//交换父子位置
			k /= 2;	//数值对应id改变
		}
	}
	
	//下沉
	void sink(int k){
		while(k *2 <= m_length){	//循环至最后一个节点截止
			int j = 2*k;
			if (j < m_length && (pArray[j] < pArray[j + 1])) j++;	// 这里先比较左子树和右子树的大小,将最大的那个键记录下来再和父节点比较
			if (pArray[k] > pArray[j]) break;	// 和父节点比较如果父节点比最大的子节点还要大,则直接退出循环
			swap(pArray[k], pArray[i]);	// 如果父节点比子节点小则交换
			k = j;
		}
	}
	
	//插入insert
	void insert(int v){
		pArray[m_length++] = v;
		sink(m_length);
	}
	
	//删除delMax
	int delMax(){
		int max = pArray[1];
		swap(pArray[1], pArray[m_length--]);
		pArray[m_length+1] = NULL;
		swim(1);
		return	max;
	}
	
	// 判断是否为空
	bool isEmpty() {
		return m_length == 0;
	}

	int size() {
		return m_length;
	}
}

参考:
1.C++实现优先队列
2.优先级队列详解

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