java 堆排序

1、基本思想:

  堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種,對直接選擇排序的有效改進。可以利用數組的特點快速定位指定索引的元素。堆分爲大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,需要使用的就是大根堆,因爲根據大根堆的要求可知,最大的值一定在堆頂。

  堆的定義下:具有n個元素的序列 (h1,h2,...,hn),當且僅當滿足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,...,n/2)時稱之爲堆。在這裏只討論滿足前者條件的堆。由堆的定義可以看出,堆頂元素(即第一個元素)必爲最大項(大頂堆)。完全二 叉樹可以很直觀地表示堆的結構。堆頂爲根,其它爲左子樹、右子樹。

  思想:初始時把要排序的數的序列看作是一棵順序存儲的二叉樹,調整它們的存儲序,使之成爲一個 堆,這時堆的根節點的數最大。然後將根節點與堆的最後一個節點交換。然後對前面(n-1)個數重新調整使之成爲堆。依此類推,直到只有兩個節點的堆,並對 它們作交換,最後得到有n個節點的有序序列。從算法描述來看,堆排序需要兩個過程,一是建立堆,二是堆頂與堆的最後一個元素交換位置。所以堆排序有兩個函數組成。一是建堆的滲透函數,二是反覆調用滲透函數實現排序的函數。

2、實例

初始序列:46,79,56,38,40,84

  建堆:

   交換,從堆中踢出最大數

依次類推:最後堆中剩餘的最後兩個結點交換,踢出一個,排序完成。

3.算法實現:

public class sort {// 堆排序

	private static int[] sort = new int[] { 1, 0, 10, 20, 3, 5, 6, 4, 9, 8, 12, 17, 34, 11 };

	public static void main(String[] args) {
		buildMaxHeapify(sort);
		heapSort(sort);
		print(sort);
	}

	private static void buildMaxHeapify(int[] data) {
		// 沒有子節點的才需要創建最大堆,從最後一個的父節點開始
		int startIndex = getParentIndex(data.length - 1);
		// 從尾端開始創建最大堆,每次都是正確的堆
		for (int i = startIndex; i >= 0; i--) {
			maxHeapify(data, data.length, i);
		}
	}

	/**
	 * 創建最大堆
	 * @paramheapSize需要創建最大堆的大小,一般在sort的時候用到,因爲最多值放在末尾,末尾就不再歸入最大堆了
	 * @paramindex當前需要創建最大堆的位置
	 */
	private static void maxHeapify(int[] data, int heapSize, int index) {
		// 當前點與左右子節點比較
		int left = getChildLeftIndex(index);
		int right = getChildRightIndex(index);

		int largest = index;
		if (left < heapSize && data[index] < data[left]) {
			largest = left;
		}
		if (right < heapSize && data[largest] < data[right]) {
			largest = right;
		}
		// 得到最大值後可能需要交換,如果交換了,其子節點可能就不是最大堆了,需要重新調整
		if (largest != index) {
			int temp = data[index];
			data[index] = data[largest];
			data[largest] = temp;
			maxHeapify(data, heapSize, largest);
		}
	}

	/**
	 * 排序,最大值放在末尾,data雖然是最大堆,在排序後就成了遞增的
	 */
	private static void heapSort(int[] data) {
		// 末尾與頭交換,交換後調整最大堆
		for (int i = data.length - 1; i > 0; i--) {
			int temp = data[0];
			data[0] = data[i];
			data[i] = temp;
			maxHeapify(data, i, 0);
		}
	}

	/**
	 * 父節點位置
	 */
	private static int getParentIndex(int current) {
		return (current - 1) >> 1;
	}

	/**
	 * 左子節點position注意括號,加法優先級更高
	 */
	private static int getChildLeftIndex(int current) {
		return (current << 1) + 1;
	}

	/**
	 * 右子節點position
	 */
	private static int getChildRightIndex(int current) {
		return (current << 1) + 2;
	}

	private static void print(int[] data) {
		int pre = -2;
		for (int i = 0; i < data.length; i++) {
			if (pre < (int) getLog(i + 1)) {
				pre = (int) getLog(i + 1);
				System.out.println();
			}
			System.out.print(data[i]+ " ");
		}
	}

	/**
	 * 以2爲底的對數
	 */
	private static double getLog(double param) {
		return Math.log(param) / Math.log(2);
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章