在了解堆之前,需要了解一種資料結構:優先佇列。
普通的佇列是一種先進先出的資料結構,元素在佇列尾追加,而從佇列頭刪除。在優先佇列中,元素被賦予優先順序。當訪問元素時,具有最高優先順序的元素最先刪除。優先佇列具有最高端先出 (first in, largest out)的行為特徵。因此,優先佇列必須支援兩種操作:刪除最大元素和插入元素。
而堆就是一種可以高效地實現刪除最大元素和插入元素的資料結構。
堆通常是乙個可以被看做一棵樹的陣列物件。堆總是滿足下列性質:
1.堆中某個節點的值總是不大於或不小於其父節點的值;
2.堆總是一棵完全二叉樹。
將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。
一般只需要用陣列來儲存堆中的元素就可以了,在乙個堆中,位置k的結點的父結點的位置為⌊k/2⌋,而它的兩個子結點的位置則分別為2k和2k+1,因此可以通過計算陣列的索引在樹中上下移動:從a[k]向上一層就令k等於k/2,向下一層就令k等於2k或2k+1。
由堆的概念可知,堆中各結點的值需要按一定規律排列,為了使堆中各結點的值按最大堆或者最小堆那樣排序,在堆這種資料結構中有兩種重要操作(以最大堆為例):
1.如果堆的有序狀態因為某個結點變得比它的父結點更大而被打破,那麼就需要通過交換它和它的父結點來修復堆,即上公升操作。
private void swim(int k)
}
這裡補充一下堆實現的比較和交換方法
private boolean less(int i,int j)
private void exch(int i,int j)
2.如果堆的有序狀態因為某個結點變得比它的兩個子結點或者其中之一更小了而被打破了,那麼可以通過將它和它的兩個子結點中的較大者交換來恢復堆,即下沉操作。
private void sink(int k)
if(!less(k,j))
exch(k,j);
k = j;
}}
最大堆進行公升序排序的基本思想:
① 初始化堆:將數列a[1…n]構造成最大堆。
② 交換資料:將a[1]和a[n]交換,使a[n]是a[1…n]中的最大值;然後將a[1…n-1]重新調整為最大堆。 接著,將a[1]和a[n-1]交換,使a[n-1]是a[1…n-1]中的最大值;然後將a[1…n-2]重新調整為最大值。 依次類推,直到整個數列都是有序的。
public static void heapsort(comparable a)
while (n > 1)
}private static boolean less(comparable v,comparable w)
private static void exch(comparable a,int i,int j)
//元素上浮操作
public static void swim(comparable a,int k)
}//元素下沉操作
public static void sink(comparable a,int k,int n)
if (!less(a[k],a[j]))
exch(a,k,j);//否則交換當前節點和其最大子節點的位置
k = j;
}}
堆與堆排序
二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足二個特性 1 父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值。2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 當父結點的鍵值總是大於或等於任何乙個子節點的鍵值時為最大堆。當父結點的鍵值總是小於或等於任何乙個子節點的鍵值時...
堆與堆排序
堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。堆排序是就地排序,輔助空間為o 1 它是不穩定的排序方法。排序的穩定性是指如果在排序的序列中,存在前後相同的兩個元素的話,排序前 和排序後他們的相對位置不發生變化 先說說什麼是堆,堆通常是乙個可以被看做一棵樹的陣列物...
堆與堆排序
堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。學習堆排序前,先講解下什麼是資料結構中的二叉堆。二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足二個特性 1 父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值。2 每個結點的左子樹和右子樹都是乙個二叉堆...