堆排序(heapsort)是指利用堆積樹(堆)這種資料結構所設計的一種排序演算法,可以利用陣列的特點快速定位指定索引的元素。
要理解排序演算法首先要知道堆的定義:堆 即一顆完全二叉樹,樹中任乙個非葉子節點的關鍵字均不大於(或者均不小於)其左右孩子(若存在)節點的關鍵字。
比如說想下面這樣的完全二叉樹就叫最小堆:
(圖1)
其中根部元素比葉子節點元素都要小,反之就是最大堆。
堆排序演算法的基本思想就是利用堆的特性,保證每次取出來的根部元素是所有元素集合裡面的最大元素(或者是最小元素)。取出根部元素後重新利用調整演算法調整堆的結構使得其保持最大(最小)堆的形態。
現在明白了堆排序的原理下面乙個要解決的問題就是怎麼儲存這個堆結構。傳統儲存一棵樹的辦法通常是用鍊錶,但是那樣會變的很複雜,其實如果我們仔細觀察堆的結構就會發現他是一顆完全二叉樹。圖1就是一顆完全二叉樹,從根節點開始從左到右給每層的節點進行編號後我們發現編號是連續的,9(0) 12(1) 11(2)33(3) 29(4),所以我們可以用乙個陣列來儲存這棵樹。對於每個節點i我們可以得到他的根節點的陣列下標是(i-1)/2,這點很重要!
堆的儲存示意圖:
(圖2)
現在我們搞清楚了堆的儲存結構,那麼問題就變得簡單了,因為我們只是對乙個陣列操作,但是需要一點想象力,想象我們在對樹操作。
堆的操作:
插入插入乙個資料到堆當中,首先把這個數放到堆的末端,也就是陣列的末端。查詢他的父節點,比較兩者的大小,如果不滿足堆的定義,那就交換他們,否則不交換直接插入。
比如我們要在上面的堆中插入15,首先15的下標位置是5,根節點是(5-1)/2=2 也就是元素11,11比15小所以不發生改變。但是如果我們要插入6,同樣先和根節點比較,6<11,所以交換他們,如下圖:
(圖3)
再次比較6和其根節點9發現還是不符合條件,所以再次交換他們的位置,發現6到達根部所以插入結束。
圖4刪除
搞懂上面的插入操作後其實刪除的原理也是一樣的,每次刪除的都是堆根部的節點, 刪除根部元素 後我們把最後乙個元素x放到根部,然後我們的任務就是比較x是否小於他的兩個子節點,如果滿足不做修改,不滿足則和其中較小的那個子節點交換,直到元素x找到自己的位置。比如上面的圖4,刪除6後,我們把11放到根節點的位置。把11和其葉子節點中較小的元素9相比,發現9較小,所以交換11和9。此時11的下標是最後乙個元素,所以不再比較,調整完成。如果11的子節點依然比他小,那麼繼續交換,直到11比他的葉子節點都要小。
初始化堆
堆的初始化也很簡單,一直執行插入堆操作就可以得到初始化好的堆。
堆排序而堆排序實質就是不斷的執行刪除堆中元素的操作。
堆排序python理解 堆排序Python實現
def heap sort nos global size size len nos print the size of the list is d size build heap size,nos for i in range size 1,0,1 nums 0 nums i nums i num...
徹底理解堆排序
堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即a parent i a i 在陣列的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。既然是堆排序,自然需要先建立乙個堆,而建堆的核心內容是調整堆,使二叉樹滿足堆的定義 每個節點的...
自己還不會的堆排序
之前堆排序我只聽說過,但是還一直沒有學到,這次來學習一下。那我們就來說說堆是什麼吧 堆 堆通常是乙個可以被看做一顆完全二叉樹的陣列物件,它的特點是子節點的鍵值或索引總是小於等於 或大於等於 它的父節點。這麼說就是要麼一定比父節點及其直屬關係 我發明的詞懂就好 的節點大或小 根節點最大的堆叫最大堆或大...