操作
插入:空穴上滤策略,新元素在堆中上滤直到找出正确位置。
删除最小者(DeleteMin):返回并删除队列中最小的元素,将堆中最后一个元素放入合适位置,空穴下滤策略。
限制:不能进行Find操作。
实现方式
1.利用简单链表,在表头O(1)插入,遍历删除最小元;或者,始终让链表有序,则插入O(N),删除O(1)。因为插入多于删除,所以前者更好。
2.利用二叉查找树,插入和删除都是O(logN),利用二叉查找树有些大材小用,因为它支持许多不需要的操作。
3.二叉堆,本文所讲。
二叉堆性质
- 结构性质
堆是一颗除底层外被完全填满的二叉树,底层上的元素从左到右填入,这样的树被称为完全二叉树。
一颗高为h的完全二叉树有2^h到2^h-1个节点,即完全二叉树的高为logN,显然是O(logN)。
完全二叉树很有规律,所以可以使用数组而不需要指针来表示:
对于数组任一位置i,左二子在2i上,右儿子在(2i + 1)中,父亲在i/2上。
一个堆数据结构由一个数组,一个代表最大值的整数,以及当前的堆;实现方法存在的问题:最大的堆需要事先估计。 - 堆序性质
最小或最大元在根上,可以快速找到。
代码:主要是插入和删除并返回最小元的操作。
#include <iostream>
using namespace std;
typedef struct HeapStruct
{
int m_capacity;
int m_size;
int* m_array;
} *PriorityQueue;
PriorityQueue Initialize(int capacity);
void Destroy(PriorityQueue H);
void MakeEmpty(PriorityQueue H);
void Insert(PriorityQueue H, int x);//上滤
int DeleteMin(PriorityQueue H);
int FindMin(PriorityQueue H);
bool IsEmpty(PriorityQueue H);
bool IsFull(PriorityQueue H);
int main()
{
}
PriorityQueue Initialize(int capacity)
{
PriorityQueue H = new HeapStruct;
if (capacity < 0)
cout << "堆容量要大于0" << endl;
H->m_array = new int[capacity];
H->m_capacity = capacity;
H->m_size = 0;
H->m_array[0] = -9999999;//MinData,标志,相当于哨兵,链表中的头结点
return H;
}
void Insert(PriorityQueue H, int x)
{
int i;
if (IsFull(H))
{
cout << "堆已满,无法插入" << endl;
return;
}
//空穴位置;父节点>x;上滤。
//此处类似于插入排序,避免交换操作。
//注意H->m_arr[0]为标记,小于堆中的任何元素,用来跳出for循环
for (i = ++H->m_size; H->m_array[i / 2] > x; i /= 2)
{
H->m_array[i] = H->m_array[i / 2];//父下移,移出空位
}
H->m_array[i] = x;//填入新元素
}
int DeleteMin(PriorityQueue H)
{
int i, Child;
int MinElement = H->m_array[1];
int LastElement = H->m_array[--H->m_size];
if (IsEmpty(H))
{
cout << "堆为空,删除失败" << endl;
return H->m_array[0];
}
for (i = 1; i * 2 <= H->m_size; i = Child)
{
//找到空穴的较小儿子,以便空穴下滤
Child = i * 2;
if (Child != H->m_size && H->m_array[Child + 1] < H->m_array[Child])
Child++;
//类似于插入排序
if (LastElement > H->m_array[Child])//堆中最后一个元素大于空穴的儿子,移出空位
H->m_array[i] = H->m_array[Child];
else//堆中最后一个元素小于空穴的儿子,停止下滤,跳出循环之后,最后一个元素填入空位
break;
}
H->m_array[i] = LastElement;//入位
return MinElement;
}