使用樹組表示的完全二叉樹的下表有如下規律:
0
1 2
3 4 5 6
7 8 ...
其中針對於k節點,其父節點是 (k-1)/2 (注意: 0節點除外)
對於k節點,其兩個兒子節點分布是: left = 2*k + 1 ; right = 2 *k + 2;
大根堆兩個主要算法:
- 向上調整算法: 主要用於插入新元數的時候;
- 向下調整算法: 用於從數組創建一個大根堆,或者刪除元素的時候;
最后一個節點是heapSize -1 那么最后一個節點的父節點就是最后一個非葉子節點:(完全二叉樹規律);
最后一個非葉子節點是(heapSize - 2)/2;
package BaseDataStructure;
import java.util.Arrays;
public class Heap {
int[] arr = new int[10];
int heapSize = 0;
public void push(int value) {
arr[heapSize++] = value;
adjustUp((heapSize-2)/2);
}
public void poll(){
swap(0, heapSize-1);
heapSize --;
adjustDown(0);
}
// 構建一個最大堆的過程:就是從后往前
// 針對每個非葉子節點,做向下調整算
// 參數是:將傳如數組,構建大根堆。
public void buildMaxHeap(int[] _arr){
arr = _arr;
heapSize = _arr.length;
// 找到非葉子節點,然后向下調整;
for(int i = (arr.length -2)/2; i >= 0; i --){
adjustDown(i);
}
}
// 向下調整算法
public void adjustDown(int k){
// 非葉子節點,不用向下調整。
// 判斷葉子節點:(堆大小是1 或 就一般的最后一個節點的父節點之后的節點都是葉子)
if(heapSize == 1 || k > (heapSize-2)/2 )
return;
int left = 2*k +1, right = 2 * k + 2, largest = left;
if(right < heapSize && arr[right] > arr[left]){
largest = right;
}
if(arr[largest] > arr[k]){
swap(largest, k);
adjustDown(largest);
}
}
// 向上調整算法
public void adjustUp(int k){
if(k < 0)
return;
int left = 2 * k + 1, right = 2 * k +2, largest = left;
if(right < heapSize && arr[right] > arr[left]){
largest = right;
}
if(arr[largest] > arr[k]){
swap(largest, k);
adjustUp((k-1)/2);
}
}
void swap(int i, int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// 排序只需要一直刪除,堆頂元素, 放到堆末尾;
// 大根堆,就能進行從小到大排序。
void sort(){
for(int i = 0; i < arr.length; i++){
poll();
}
}
}
import java.util.Arrays;
public class TestDemo{
public static void main(String[] args) {
Heap heap = new Heap();
heap.buildMaxHeap( new int[]{3,4,5,6,9} );
System.out.println( Arrays.toString(heap.arr) );
heap.sort();
System.out.println( Arrays.toString(heap.arr ));
}
}