堆是一棵完全二叉树,我们实现堆可以通过数组的方式来实现。在此之前,我们先了解一些数组实现二叉树的知识点。
下面是亲属节点下表公式。
Parent(r) = (r-1)/2; r != 0;
LeftChild(r) = r*2+1; 2*r+1 < n;
RightChild(r) = 2*r +2; 2*r+2 < n;
LeftSibling(r) = r - 1; r%2 == 0 and r != 0;
RightSibling(r) = r + 1; r%2 == 1 and r + 1 < n;
这些公式对下面堆的实现很有用,下面是整形最大堆的实现
class Heap{
private:
int *heap;
int length;
int maxSize;
void siftDown(int pos){
while(!isLeaf(pos)){
int l = leftChild(pos);
int r = rightChild(pos);
if(r < length && heap[r] > heap[l]){
l = r;
}
if(heap[pos] < heap[l]){
swap(heap,pos,l);
pos = l; //move down
}else{
return;
}
}
}
void swap(int * A,int i,int j){
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
public:
Heap(int *array,int n,int max){
this->heap = array;
this->length = n;
this->maxSize = max;
buildHeap();
}
int size() const{
return length;
}
bool isLeaf(int pos) const{
return pos >= length/2 && pos < length;
}
int leftChild(int pos) const{
return 2*pos + 1;
}
int rightChild(int pos) const{
return 2*pos + 2;
}
int parent(int pos) const{
if(pos != 0){
return (pos-1)/2;
}
return 0;
}
void buildHeap(){
for(int i = length/2 -1 ; i >= 0; i--){ //这些非叶节点的所在位置
siftDown(i);
}
}
void insert(const int element){
if(length == maxSize){
return;
}
int curr = length;
length ++;
heap[curr] = element;
while(curr != 0 && heap[curr] > heap[parent(curr)]){
swap(heap,curr,parent(curr));
curr = parent(curr);
}
}
int removeFirst(){
if(length <= 0){
return -1;
}
swap(heap,0,--length);
if(length != 0){
siftDown(0);
}
return heap[length];
}
};