二叉樹(堆和優先佇列)
阿新 • • 發佈:2018-12-20
堆是一種特殊的二叉樹。
最小值堆:最小值堆的特性。
對於堆的任意非葉節點K,K的值總是小於或者等於左右子節點。
K <= 左節點;K <= 又節點;
堆例項:
堆實際上是一個完全二叉樹(若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。)可以用陣列表示。
堆中儲存是區域性有序的。
建立堆:
交換建立堆,交換有2,1)向下交換,2)向上交換。
1)向下交換。
假設根的左右子樹都已是堆,並且根元素為R,此時有2種情況。
(1)R的值小於或者等於左右子結點,此時堆完成。
(2)R的值大於其中一個或者兩個子女,此時R應該與兩個子女中較小的一個交換,結果得到一個新堆,
R到達新位置後繼續和其兩個子女,如果R小於或者等於其左右子女,建堆完成,否則重複上一過程,直到
R小於或等於其左右子女,或R成為新的葉結點。
堆的陣列實現:
public abstract class AbstractHeap<T extends Comparable<T>> implements Heap<T> { //最大堆大小 private static final int MAX_SIZE = Integer.MAX_VALUE; //陣列大小 protected int size; //堆中陣列個數 protected int currentSize; //儲存堆的資料 protected T[] data; AbstractHeap(){ this(0,16,null); } AbstractHeap(T[] data){ this(data.length,data.length,data); } AbstractHeap(int currentSize,int size,T[] data){ this.currentSize = currentSize; this.size = size; this.data = data; if (data != null) //根據給定陣列 建立堆 buildHeap(data); } }
用給定的陣列建立堆,從堆中第一個分支結點,從下往上網上交換建立堆:
private void buildHeap(T[] t){
if (t.length > 1){
//從下到上第一個分支結點
int pos = t.length / 2 - 1;
for (int i = pos ; i >= 0 ; i -- ){
//向下交換
siftDown(i);
}
}
}
交換函式:
void siftDown(int pos) { // pos為第一個分支結點位置 int tmp = pos; // j為其左結點 int j = tmp * 2 + 1; //儲存當前結點值 T tmpNode = data[tmp]; while ( j < currentSize){ //j < currentSize - 1 防止右結點不存在,j+1 = tmp *2 +1 ,data[j+1] 為右結點 if (j < currentSize - 1 && data[j].compareTo(data[j+1]) == 1){ //若右結點值比較小,j++ j++; } if (tmpNode.compareTo(data[j]) == 1){ //若當前結點值大於左右結點中最小的值,將最小的哪個結點值上移當前結點, data[tmp] = data[j]; //tmp 為上移結點下標 tmp = j; j = j * 2 + 1; } //如果當前結點值小於其左右子女中最小的,建堆完成,跳出迴圈 else break; //將當前結點值 賦值給上移結點 data[tmp] = tmpNode; } }
2)向上交換
在堆中新增值時,採用向上交換:
public boolean insert(T t) {
if (t == null){
return false;
}
if (currentSize == size){
return false;
}
//直接將新增值放到陣列的最後一個位置,並向上交換
data[currentSize] = t;
siftUp(currentSize);
currentSize ++;
return true;
}
void siftUp(int pos) {
//當前位置下標
int tmp = pos;
//父結點下標
int j = (pos - 1) / 2;
//當前結點
T tmpNode = data[tmp];
while (j >= 0){
//如果當前結點值小於父結點,當前結點值向上移動,直到根結點或者當前結點值打於根結點值跳出迴圈
if (tmpNode.compareTo(data[j]) == -1){
data[tmp] = data[j];
tmp = j;
j = j / 2 - 1;
}else break;
tmpNode = data[tmp];
}
}
建立堆可以根據已有資料建立採用向下移動建立,也可以一個一個的插入值,採用向上移動的方法建立堆。
小結:
堆的特性,父結點的值小於左右子女結點值。
堆保持區域性有序性,可以用左優先佇列。
堆排序時間複雜度為O(n)