3.建堆
4.堆排序演算法
(二叉)堆資料結構是一種陣列物件,可以被視為一顆完全二叉樹。表示堆的陣列a是乙個具有兩個屬性的物件:length[a]是陣列中元素個數,heap-size[a]是存放在a中的堆的元素個數,heap-size[a]<=length[a]。樹的根表示為a[1],給定某結點下標i,其父節點parent(i) = i/2(向下取整),left[i] = 2i,right[i] = 2i+1。
max-heapify是對最大堆操作的重要子程式,其輸入為乙個陣列a和下標i,當a[i]小於其子女時可能違背最大堆性質,為了保持堆的性質,呼叫max-heapify,max-heapify讓a[i]在最大堆中「下降」,使以i為根的子樹成為最大堆。具體的偽**如下所示:
max_heapify(a,i)
1 l ← left(i)
2 r ← right(i)
3if l <= heap-size[a] and
a[l] > a[i]
4 then largest ← l
5else largest ← i
6if r <= heap-size[a] and
a[r] > a[largest]
7 then largest ← r
8if largest ≠ i
9 then exchange a[i] ‹-› a[largest]
10 max_heapify(a,largest)
下圖描述了max_heapify的過程:
在演算法中,每一步,從元素a[i],a[left(i)]和a[right(i)]中找出最大的,將下標存在largest中,如果a[i]是最大的,即i=largest,則以i為根的子樹已經是最大堆,如果a[i]不是最大的,則交換a[i]與a[largest],將i「下降」,堆該子樹遞迴呼叫max-heapify。
當max-heapify作用在一棵以結點i為根、大小為n的子樹上時,其執行時間為調整元素a[i]、a[left(i)]和a[right(i)]的關係所用時間為θ(1)的常數時間,再加上對以i的某個子節點為根的子樹遞迴呼叫max-heapify所需的時間。i結點的子樹大小至多為2n/3(最壞情況發生在底層恰好半滿的時候),那麼max-heapify的執行時間如下:t(
n)≤t
(2n/
3)+θ
(1) t(n
)≤t(
2n/3
)+θ(
1)根據主定理的情況2,該遞迴式的解為 t(
n)=o
(lgn
) t(n
)=o(
lgn)
可以說,max-heapify作用於乙個高度為h的結點所需的執行時間為o(h)。
有了上述的max-heapify方法來保持堆的性質,我們就可以自底向上的用max-heapify來將乙個陣列a[1,2,…n]變成乙個最大堆。由完全二叉樹的性質可知,子陣列a[(n/2+1)..n]中的元素都是樹中的葉子,因此每個都可以看做是只含乙個元素的堆。過程build-max-heap對樹中每乙個其他結點都呼叫一次max-heapify。具體演算法如下:
build-max-heap(a)
1 heap-size[a] ← length[a]
2 for i ← [length[a]/2] downto 1
3 do max-heapify(a,i)
下圖給出建堆過程的乙個例子:
很簡單的能得到build-max-heap執行時間的乙個上界:每次呼叫max-heapify的時間為o(lgn),共有n次呼叫,故執行時間為o(nlgn)。這個界雖然正確,但是並不緊確,我們可以得到乙個更緊確的界。在樹中,不同高度的結點處執行max-heapify的時間不同,而大部分結點的高度較小。我們可以知道這樣乙個性質:乙個n元素堆的高度為[lgn],並且在任意高度h上,至多有[n/2^(h+1)]個結點,於是我們可以將build-max-heap的代表表達為: ∑h
=0[l
gn][
n2h]
o(h)
=o(n
∑h=0
[lgn
][n2
h]) ∑h=
0[lg
n][n
2h]o
(h)=
o(n∑
h=0[
lgn]
[n2h
])根據公式 ∑k
=0∞k
xk=x
(1−x
)2∑ k=
0∞kx
k=x(
1−x)
2帶入x=1/2,可得 o(
n∑h=
0[lg
n][n
2h])
=o(n
) o(n
∑h=0
[lgn
][n2
h])=
o(n)
開始時,堆排序演算法先用build-max-heap將輸入陣列a[1..n]構造成乙個最大堆,因為陣列中最大元素在根a[1],所以可以通過將a[1]與a[n]互換,此時從堆中「去掉」結點n,可以很容易的將a[1..(n-1)]建造成最大堆。堆排序演算法重複這個過程,堆的大小從n-1降到2,即可獲得最終的排序結果,具體演算法如下:
heapsort(a)
1 build-max-heap(a)
2 for i ← length[a] downto2
3 do exchange a[1] a[i]
4 heap-size[a] ← heap-size[a-1]
5 max-heapify(a,1)
下圖給出乙個排序的例子:
heapsort過程的時間代價為o(nlgn)。其中呼叫build-max-heap的時間為o(n),n-1次max-heapify呼叫中每一次的時間代價為o(lgn)。
資料結構 堆與堆排序
堆其實是從完全二叉樹演變過來的並且用來儲存資料的,什麼是完全二叉樹呢?完全二叉樹就是 若設二叉樹的深度為h,除第h層外,其它各層 1 h 1 的結點數都達到最大個數,第h層所有的結點都連續集中 在最左邊,這就是完全二叉樹。我們知道二叉樹可以用陣列模擬,堆自然也可以。現在讓我們來畫一棵完全二叉樹 從圖...
堆資料結構與堆排序
堆資料結構 堆 二叉堆 是近似的完全二叉樹,最底層允許不滿,堆的相關,陣列長度length,heap size有效長度 堆的有效元素,未排序的數目 heap size堆雖然很像二叉樹,但是我的理解就是用二叉樹的邏輯,但是最主要的區別在,堆的儲存是用陣列,只是用下標來幫助理解 堆的儲存結構 從上往下,...
資料結構與演算法16 堆排序
毫無疑問,排序兩個字沒必要去死磕,這裡的重點,在於排序的方式,堆排序,就是以堆的形式去排序,毫無疑問,了解堆很重要。那麼,什麼是堆呢?這裡,必須引入乙個完全二叉樹的概念,然後過渡到堆的概念。上圖,就是乙個完全二叉樹,其特點在於 從作為第一層的根開始,除了最後一層之外,第n層的元素個數都必須是2的n次...