1. 程式人生 > >大頂堆在Java中的一種優雅實現

大頂堆在Java中的一種優雅實現

既然小頂堆已經實現出來,那麼同理大頂堆也順理成章實現出來,只需稍微改動幾個關鍵部門的程式碼。

/**
 * 大頂堆/最大堆實現
 * 
 * @author stephenshen
 *
 */
public class MaxHeap {
	// 堆得儲存結構:陣列
	private int[] data;

	/**
	 * 構造方法:傳入一個數組,並轉換為一個最大堆
	 * 
	 * @param data
	 */
	public MaxHeap(int[] data) {
		this.data = data;
		buildHeap();
	}

	/**
	 * 將陣列轉化為最大堆
	 */
	private void buildHeap() {
		//完全二叉樹只有陣列下標小於或等於 (data.length) / 2 - 1 的元素有孩子結點,遍歷這些結點。
		//比如上面的圖中,陣列有10個元素, (data.length) / 2 - 1的值為4,a[4]有孩子結點,但a[5]沒有
		//即,從下自上開始堆化(從最下層非葉子節點開始)
		for (int i = (data.length) / 2 - 1; i >= 0; i--) {
			heapify(i);
		}
	}

	/**
	 * 從當前節點開始堆化
	 * 
	 * @param i
	 */
	private void heapify(int i) {
		// 獲取左右節點陣列下標
		int l = left(i);
		int r = right(i);

		// 假定的當前節點、左子節點、右子節點中 最大值的下標
		int biggest = i;

		// 存在左子節點,且左子節點的值大於當前節點的值
		if (l < data.length && data[l] > data[i])
			biggest = l;

		// 存在右子節點,且右子節點的值大於當前節點的值
		if (r < data.length && data[r] > data[i])
			biggest = r;

		// 左右結點的值都小於根節點,直接return
		if (i == biggest)
			return;

		// 將最大值與當前節點互換位置
		swap(i, biggest);

		// 從之前最大值節點位置重新堆化
		heapify(biggest);
	}

	/**
	 * 獲取右節點的陣列下標
	 * 
	 * @param i
	 * @return
	 */
	private int right(int i) {
		return (i + 1) << 1;
	}

	/**
	 * 獲取左節點的陣列下標
	 * 
	 * @param i
	 * @return
	 */
	private int left(int i) {
		return ((i + 1) << 1) - 1;
	}

	/**
	 * 交換元素位置
	 * 
	 * @param i
	 * @param j
	 */
	private void swap(int i, int j) {
		int tmp = data[i];
		data[i] = data[j];
		data[j] = tmp;
	}

	/**
	 * 獲取堆中最大元素,即根元素
	 * 
	 * @return
	 */
	public int getRoot() {
		return data[0];
	}

	/**
	 * 替換根元素,並重新heapify
	 * 
	 * @param root
	 */
	public void setRoot(int root) {
		data[0] = root;
		heapify(0);
	}
}