优先队列是一种支持插入新元素和删除最大元素的数据结构。它和我们之前学过的队列和栈很相似,优先队列是队列和栈的拓展。而堆是支持优先队列的操作的一种数据结构。实现堆的方法有好几种,第一:我们可以使用链表,以O(1)时间插入,以O(N)时间删除。第二:使用二叉树,二叉树的所有操作需要,但是插入和删除操作却会导致二叉树严重的不平衡,那AVL树呢?插入和删除的操作需要
,而且不会破坏树的平衡性,可以是可以,但是太过复杂。那怎么实现呢?我们往往使用基于数组实现的堆的数据结构。为什么呢?堆是一颗完全二叉树(也就是说插入和删除操作的时间复杂度都为
),这也是堆的结构性。堆也有堆序性,也就说堆中任意节点的键值都大于它的孩子的键值。我们往往把这种堆叫大堆。那么堆一般在哪里使用呢?操作系统中使用优先级调度算法堆进程进行调度等等。现在就让我们看看堆怎么实现吧!!
我们首先应该知道位置为k的节点,其父节点为[k/2],其左孩子的位置为2k.其右孩子的位置为2k+1.
堆的接口:
class Heap {
public:
Heap(std::vector& _heap) :heap(_heap) {};
public:
void Build_Heap();
bool IsEmpty()const;
void Insert(const ElemType key);
void Delete();
void Display()const;
bool Find(const ElemType key)const;
ElemType FindMax()const;
void Heap_Sort();
private:
std::vectorheap;
void swap(int i, int j);
void Heapify(int i, size_t size);
};
堆的删除操作:我们删除堆中的最大元素时,堆中少一个元素,这个很简单,但是这时堆的根节点为空,我们必须移入一个元素来填充这个空穴。怎么移入呢?我们可以把空穴的两个孩子中最大的元素移入其中,慢慢的向下移动,知道堆中的最后一个元素可以放入空穴中,此过程叫做下滤。
void Heap::Delete() {
if (!IsEmpty()) {
int i = 0;
int child = 0;
auto lastelem = heap[heap.size()-1];//最后的元素
for (i = 1; i * 2 <= heap.size(); i = child) {
child = i * 2;
if ((child != heap.size()-1) && (heap[child] < heap[child + 1]))
++child;
if (lastelem >= heap[child])
break;
else
heap[i] = heap[child];
}
heap[i] = lastelem;
}
}
堆的插入操作:为将元素插入堆中,我们先在最后位置的下一个位置创建一个空穴,然后通过比较待插入元素与空穴的父节点的键值,进行向上移动,最后将待插入元素放入此空穴中,此过程叫上移。堆中的0位置相当于标记,让其为无穷大,可以让循环结束。
void Heap::Insert(const ElemType key) {
if (!IsEmpty()) {
int i = 0;
auto j = heap.size() - 1;
for (i = j; heap[i / 2] < key; i /= 2)
heap[i] = heap[i / 2];
heap[i] = key;
}
}
堆的建立与排序:
void Heap::swap(int i, int j) {
if (!IsEmpty()) {
auto temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}
void Heap::Heapify(int i, size_t size) {
if (i > size)
return;
auto c1 = i * 2;
auto c2 = i * 2 + 1;
auto max = i;
if (c1heap[max])
max = c1;
if (c2heap[max])
max = c2;
if (max != i) {
swap(max, i);
Heapify(max, size);
}
}
void Heap::Build_Heap() {
auto last_node = heap.size();
auto parernt_last_node = (last_node) / 2;
for (int i = parernt_last_node; i >= 1; --i) {
Heapify(i, heap.size());
}
}
void Heap::Heap_Sort() {
if (!IsEmpty()) {
Build_Heap();
for (int i = heap.size() - 1; i >= 0; --i) {
swap(i, 0);
Heapify(0, i);
}
}
}
此堆建立与排序,参考我的另一篇博客。
完整代码如下:
#include
#include
#include
typedef int ElemType;
const int MAX = 999;
class Heap {
public:
Heap(std::vector& _heap) :heap(_heap) {};
public:
void Build_Heap();
bool IsEmpty()const;
void Insert(const ElemType key);
void Delete();
void Display()const;
bool Find(const ElemType key)const;
ElemType FindMax()const;
void Heap_Sort();
private:
std::vectorheap;
void swap(int i, int j);
void Heapify(int i, size_t size);
};
void Heap::swap(int i, int j) {
if (!IsEmpty()) {
auto temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}
void Heap::Heapify(int i, size_t size) {
if (i > size)
return;
auto c1 = i * 2;
auto c2 = i * 2 + 1;
auto max = i;
if (c1heap[max])
max = c1;
if (c2heap[max])
max = c2;
if (max != i) {
swap(max, i);
Heapify(max, size);
}
}
void Heap::Display()const {
if (!IsEmpty()) {
for (int i = 1; i < heap.size(); ++i) {
std::cout << heap[i] << std::endl;
}
}
}
void Heap::Build_Heap() {
auto last_node = heap.size();
auto parernt_last_node = (last_node) / 2;
for (int i = parernt_last_node; i >= 1; --i) {
Heapify(i, heap.size());
}
}
bool Heap::IsEmpty()const {
return heap.size() == 0;
}
bool Heap::Find(const ElemType key)const {
if (!IsEmpty()) {
for (int i = 1; i < heap.size(); ++i) {
if (key == heap[i])
return true;
}
return false;
}
}
ElemType Heap::FindMax()const{
if (!IsEmpty()) {
return heap[1];
}
}
void Heap::Insert(const ElemType key) {
if (!IsEmpty()) {
int i = 0;
auto j = heap.size() - 1;
for (i = j; heap[i / 2] < key; i /= 2)
heap[i] = heap[i / 2];
heap[i] = key;
}
}
void Heap::Delete() {
if (!IsEmpty()) {
int i = 0;
int child = 0;
auto lastelem = heap[heap.size()-1];
for (i = 1; i * 2 <= heap.size(); i = child) {
child = i * 2;
if ((child != heap.size()-1) && (heap[child] < heap[child + 1]))
++child;
if (lastelem >= heap[child])
break;
else
heap[i] = heap[child];
}
heap[i] = lastelem;
}
}
void Heap::Heap_Sort() {
if (!IsEmpty()) {
Build_Heap();
for (int i = heap.size() - 1; i >= 0; --i) {
swap(i, 0);
Heapify(0, i);
}
}
}
int main(void) {
std::vectorvec{ MAX,4,7,2,5,8,3,6,9};
Heap heap(vec);
heap.Build_Heap();
heap.Display();
std::cout << "----------" << std::endl;
heap.Insert(12);
heap.Display();
std::cout << "--------------" << std::endl;
heap.Delete();
heap.Display();
std::cout << "-------------------" << std::endl;
heap.Heap_Sort();
heap.Display();
}
参考 《数据结构与算法分析——C语言描述》