資料結構之二叉堆 堆排序

2021-09-13 14:46:13 字數 2533 閱讀 1405

很久以前排序演算法的時間複雜度一直是o(n^2), 當時學術界充斥著「排序演算法不可能突破o(n^2)」的聲音,直到2023年,由d.l.shell提出了一種排序演算法,希爾排序(shell sort),才打破了這種不可能的聲音,把排序演算法的時間複雜度提公升到了o(n^3/2)!

當科學家們知道這種"不可能"被突破之後,又相繼有了更快的排序演算法,「不可能超越o(n^2)」徹底成為了歷史。

在2023年,沒錯,是55年前!堆排序這種奇思妙想的,十分精彩的,排序演算法誕生了!時間複雜度為o(nlogn),遠甩o(n^2)

由robert w. floyd(羅伯特·弗洛伊德)和j.w.j. williams(威廉士)共同發明了著名的堆排序,同時也發明了「堆」這樣的資料結構, floyd在2023年獲得了圖靈獎!真是個狼人!!(比很人還要多一點)

有時候了解下歷史,也是十分有趣的!雖然你可能會覺得並沒什麼卵用~

之前第一次聽到這個詞的時候,感覺像是一堆什麼東西,完全跟樹連想不到一起,後來才知道,原來也是一顆二叉樹,而且是完全二叉樹

堆的性質:

堆中某個節點的值總是不大於或不小於其父節點的值;

堆總是一棵完全二叉樹。

我們可以把堆,存放在乙個陣列中,根據索引來獲取節點,那麼如何通過索引表示父子關係呢?

堆是一顆完全二叉樹,所以滿足如下條件

假如當前的節點索引為:k

父節點索引:(k-1) / 2

左孩子節點:2 * k + 1

右孩子節點:2 * k + 2

根據這個規律,我們就可以用索引來計算出父子節點的位置了。這樣就能把堆存放在陣列中使用,會更加節省記憶體。

堆排序演算法就是形成乙個堆後,假如是大頂堆,堆頂肯定是最大的元素,那我們每次都把堆頂的最大元素拿走,然後把堆末尾的元素放到堆頂來,但是這個元素不一定是當前最大的,所以還要對這個元素在堆裡進行比較,把最大的元素放到堆頂,再取出來。如此我們每次取出的都是剩餘元素中最大的元素,就能得到一組從大到小有序的元素。下面我們來用大頂堆對一組資料進行堆排序計算。

資料為:[50, 10, 90, 30, 70, 40, 80, 60, 20]

演算法分為兩個部分

1.如何將一組無序的資料構建出乙個初始的大頂堆?

2.在拿走堆頂元素之後,如何計算出新的堆頂元素?

首先我們要實現乙個操作:如果乙個節點的子節點比它更大,就交換位置,如果子節點還有子節點,就要繼續比下去,直到末尾。這個操作我們稱為:heapone

public void heapone(listlist, int len, int s)

list[s] = temp;

}

實現這個操作之後,就可以開始我們的第乙個部分了,形成初始大頂堆。

從最後乙個非葉子節點開始,對該節點進行heapone,一直從下往上,直到把所有的父節點都heapone了一遍,乙個初始的大頂堆就形成了。

public void heapsort(listlist)

for (i = list.count -1; i > 0; i--)//每拿走乙個元素,都重新計算新堆

}

演算法第二部分我們把堆頂的元素取出,放到乙個臨時變數裡存著。

然後把堆的最末尾元素取出來,放到堆頂。

把堆的長度-1(因為已經取出之前的堆頂元素了)

接著對剛剛這個從末尾放到堆頂的元素,進行heapone操作,讓他跟子節點比較,把最大的元素交換到堆頂來,再次形成最大堆。

一直重複這個操作後,直到最後乙個堆頂被取出,放到陣列末尾,堆的長度也就為0了,我們的陣列也就形成了一組從大到小的數列。

如此,堆排序就完成了

堆排序效能比較穩定,時間複雜度包含初始堆+排序時重建堆為:o(nlogn)。

在遊戲開發中也會經常使用到堆

比如top k問題,從n個資料中,找出最大的前100個。

用堆來實現優先載入佇列。

a星尋路演算法中,可以用最小堆來對尋路的開放列表維護順序,把f值最小的放在堆頂,每次取出堆頂後,再heapone一次就好了。比每次都對開放列表進行排序的效能高的多。

《大話資料結構》-程杰

posted @

2019-03-25 00:32

李嘉的部落格 閱讀(

...)

編輯收藏

資料結構之二叉堆 堆排序

很久以前排序演算法的時間複雜度一直是o n 2 當時學術界充斥著 排序演算法不可能突破o n 2 的聲音,直到1959年,由d.l.shell提出了一種排序演算法,希爾排序 shell sort 才打破了這種不可能的聲音,把排序演算法的時間複雜度提公升到了o n 3 2 當科學家們知道這種 不可能 ...

資料結構之二叉堆 構建堆,堆排序

public class heap system.out.println 原始 printheapbylevel array system.out.println 最小堆 getminheap array printheapbylevel array sort array printheapbyle...

JS資料結構 二叉堆 堆排序

結構特性 這是一種特殊的二叉樹,他是乙個完全的二叉樹,樹的每一層都有左右子樹,並且最後一層的葉節點盡可能都是左子樹 堆特性 二叉堆不是最小堆就是最大堆。最小堆允許快速找到樹的最小值,最大堆允許找到樹的最大值。所有節點都大於等於 最大堆 或者小於等於 最小堆 每個他的子樹 1.正常的情況下,陣列可以通...