簡介
當一棵二叉樹的每個結點都大於它的兩個子結點時,被稱為堆有序;
如果我們用指針來表示堆有序的二叉樹,那么每個元素都需要三個指針來找到它的上下結點;但是如果我們使用完全二叉樹,只用數組而不需要指針就可以表示;
什么是最小堆呢?
最小堆就是在二叉堆的基礎上,符合了每個結點都比他的子結點要小的規則!
我們會遇到這兩種情況,這也是最小堆中特別要注意的兩種實現:
- 上浮:從下至上恢復堆的順序,在當某個節點的優先級上升時;
- 下沉:從上至下恢復的順序,當某個節點的優先級下降的時候;
我們可以從下面的圖中觀察最小堆是如何運行的:
只要不滿足小的規則就交換
實現
1.上浮
先看上浮,其思想就是,因為是從下至上,所以根據當前結點,算出父親結點,然后跟父親結點進行比較,如果子結點小的話,則需要進行相互交換,反之不用,直到循環到下標到達結尾;
/**
* 將end到0的數據都上浮
*
* @param end
*/
void MinHeap::shiftUp(int end) {
int i = end;
while (i > 0) {
int parent = i % 2 == 0 ? i/2 - 1 : i/2;
if (heap[i] < heap[parent]) {
swap(&heap[i], &heap[parent]);
i = parent;
}
else {
--i;
}
}
}
2.下沉
接着看下沉,其思想就是,因為是從上至下,所以根據當前結點,算出左右子結點,然后跟當前結點進行比較,如果左右結點小,這里需要注意的是,取左右子結點中小的進行交換,因為其中必然會有三者之中的最小值,反之不用,直到循環到下標到達0;
/**
* 將start到end的數據都往下沉
* 將子結點和父結點進行比較
*
* @param start <#start description#>
* @param end <#end description#>
*/
void MinHeap::shiftDown(int start, int end) {
int i = start;
while (i < end) {
int lchild = i*2 + 1, rchild = i*2 + 2;
if ((heap[i] > heap[lchild] && lchild < currentSize) || (heap[i] > heap[rchild] && rchild < currentSize)) {
bool leftSmall = heap[lchild] < heap[rchild];
if (leftSmall) {
swap(&heap[i], &heap[lchild]);
i = lchild;
}
else {
swap(&heap[i], &heap[rchild]);
i = rchild;;
}
}
else {
++i;
}
}
}
3.插入刪除
還有一個需要注意的點是插入刪除;
- 插入:插到數組的最后一個位置上,增加堆大小,並且上浮;
- 刪除:將數組頭元素用數組尾元素進行替換,減小堆大小,並且下沉;
4.整體實現
//
// main.cpp
// Heap
//
// Created by George on 16/11/1.
// Copyright © 2016年 George. All rights reserved.
//
#include <iostream>
#define DefaultSize 10
#define Log(content) { std::cout << "Log:" << content << std::endl; }
class MinHeap {
public:
MinHeap(int size = DefaultSize);
~MinHeap();
inline bool isEmpty() {
return currentSize == 0;
};
inline bool isFull() {
return currentSize == maxSize;
};
bool insert(const int value);
bool removeMin();
int poll();
void shiftDown(int start, int end);
void shiftUp(int end);
void toString();
private:
int * heap;
int currentSize;
int maxSize;
void swap(int *num1, int *num2);
};
MinHeap::MinHeap(int size) : currentSize(0) {
heap = new int[size];
maxSize = size > DefaultSize ? size : DefaultSize;
}
MinHeap::~MinHeap() {
}
void MinHeap::toString() {
for (int i = 0; i < currentSize; ++i) {
std::cout << heap[i] << std::endl;
}
}
void MinHeap::swap(int *num1, int *num2) {
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
/**
* 將start到end的數據都往下沉
* 將子結點和父結點進行比較
*
* @param start <#start description#>
* @param end <#end description#>
*/
void MinHeap::shiftDown(int start, int end) {
int i = start;
while (i < end) {
int lchild = i*2 + 1, rchild = i*2 + 2;
if ((heap[i] > heap[lchild] && lchild < currentSize) || (heap[i] > heap[rchild] && rchild < currentSize)) {
bool leftSmall = heap[lchild] < heap[rchild];
if (leftSmall) {
swap(&heap[i], &heap[lchild]);
i = lchild;
}
else {
swap(&heap[i], &heap[rchild]);
i = rchild;;
}
}
else {
++i;
}
}
}
/**
* 將end到0的數據都上浮
*
* @param end
*/
void MinHeap::shiftUp(int end) {
int i = end;
while (i > 0) {
int parent = i % 2 == 0 ? i/2 - 1 : i/2;
if (heap[i] < heap[parent]) {
swap(&heap[i], &heap[parent]);
i = parent;
}
else {
--i;
}
}
}
/**
* 刪除最小值,也就是堆頂,用最大值替代,並且下沉
*
* @return <#return value description#>
*/
bool MinHeap::removeMin() {
if (currentSize == 0) {
Log("current size is 0!");
return false;
}
heap[0] = heap[currentSize-1];
--currentSize;
shiftDown(0, currentSize-1);
return true;
}
/**
* 插入值后要進行上浮
*
* @param value <#value description#>
*
* @return <#return value description#>
*/
bool MinHeap::insert(const int value) {
if (currentSize == maxSize) {
int *nHeap = heap;
heap = new int(maxSize + 10);
for (int i = 0; i < maxSize; ++i) {
heap[i] = nHeap[i];
}
delete [] nHeap;
Log("heap is resize!");
}
heap[currentSize++] = value;
shiftUp(currentSize-1);
return true;
}
/**
* 取得堆頂值
*
* @return <#return value description#>
*/
int MinHeap::poll() {
if (isEmpty()) {
Log("heap is null!");
return -1;
}
return heap[0];
}
int main(int argc, const char * argv[]) {
// insert code here...
MinHeap Heap;
Log("------------Insert------------");
int arr[8] = {8, 7, 6, 5, 4, 3, 2, 1};
for (int i = 0; i < 8; i++) {
Heap.insert(arr[i]);
}
Heap.toString();
Log("------------Remove------------");
Heap.removeMin();
Heap.toString();
Log("------------Get------------");
std::cout << "poll:" << Heap.poll() << std::endl;
return 0;
}
看結果: