1. 程式人生 > >【資料結構與演算法】最小堆 minheap

【資料結構與演算法】最小堆 minheap

最小堆與最大堆實現思路一樣,只不過順序不同,這裡只記錄最小堆。

最小堆的定義是,一棵完全二叉樹,每一個節點都大於等於其父節點。完全二叉樹是葉子都在最後一層,且儘量靠左。

實現方面可以使用連結串列或者陣列,這裡使用陣列。

如果使用陣列,那麼下標從0開始,父節點是i,則左子樹是2*i+1,右子樹是2*i+2。如果子節點是i,則父節點是(i-1)/2。

minheap的操作主要有兩個,一個是add,思路是,新建一個節點在最後,然後不斷地和父節點比較,如果小於父節點,就交換,直到大於等於或者root。

第二個操作是輸出root,那麼需要把最後一個節點移至root位置,然後重新梳理minheap,因為此時可能不再shiminheap了,梳理過程用函式minheapify實現。該函式的實現思路是傳入一個i引數,表明以i為根的子樹需要梳理,然後讓i和比i小的子節點中的較小值交換,再遞迴地梳理被交換的節點。

下面是程式碼,這裡沒有考慮一些邊界,比如陣列的大小,或者輸出空的heap的情況。

public class MinHeap {

	private int size = 0;
	private int[] heap = new int[100];
	
	public void add(int data){
		heap[size++] = data;
		int i = size - 1;
		while(i > 0 && heap[i] < heap[(i - 1) / 2]){
			swap(i, (i - 1) / 2);
			i = (i - 1) / 2;
		}
	}
	
	public int top(){
		size --;
		int r = heap[0];
		swap(size, 0);
		minheapify(0);
		return r;
	}
	
	public void minheapify(int i){
		int l = 2 * i + 1;
		int r = 2 * i + 2;
		int small = i;
		if(l < size && heap[i] > heap[l]){
			small = l;
		}
		if(r < size && heap[r] < heap[small]){
			small = r;
		}
		if(i != small){
			swap(i, small);
			minheapify(small);
		}
	}
	
	private void swap(int i, int j){
		int temp = heap[i];
		heap[i] = heap[j];
		heap[j]= temp;
	}
	
	public int size(){
		return size;
	}
}