python堆排序


堆是完全二叉樹

子樹是不相交的

 

度 節點擁有子樹的個數

滿二叉樹:

每個節點上都有子節點(除了葉子節點)

 

完全二叉樹:

葉子結點在倒數第一層和第二層,最下層的葉子結點集中在樹的左部

,在右邊的話,左子樹不能為空

 

二叉搜索樹:

左邊子節點小於父節點,右邊子節點大於父節點

 

堆:

也叫隊列,在堆尾插入,在堆頭取出

 

最大堆:

最上邊比下邊的兩個數都大,所有的節點都滿足這個規則

 

 

 

最小堆:

父節點一定比兩個子節點要小

 

特征:

堆起始坐標從1開始

如果用列表表示一個堆:

堆的坐標從1開始算

當前坐標是i

左節點坐標是2i

右節點坐標是2i+1

父節點坐標是i//2 取整

 

如果想找到最后一個帶有子節點的節點坐標:

堆的長度//2

 

[0,1,2,3,4,5]

 

[0,1,2,3,4,5,6,7]

 

   1

 2  2*1+1=3

2*2  2*2+1=5

 

0

1        2

3    4    5   6

堆的坐標從0開始算

當前坐標是i

左節點坐標是2i+1

右節點坐標是2i+2

父節點坐標是(i-1)//2 取整

 

如果想找到最后一個帶有子節點的節點:

(堆的長度-1)//2

 

父節點的位置是K//2,它的左節點是2k,右節點是2k+1

在堆里插入一個元素:上濾

最大堆:

所有的父節點必須大於它的兩個子節點

如果將新元素增加到堆的末尾:加一個88

要保證最大堆的規則,新元素和父節點調整交換的操作叫做上濾

 

 

只要插入的節點比父節點小,就不做交換了,不交換那么排序就停止了

當發生了新插入節點和父節點沒有交換的情況,那么上濾過程及結束了

 

刪除根元素:下濾

刪除堆頂元素,兩個子元素比較,大的上去,空出的元素的兩個子元素繼續比較,大的再上去。。。

 

 

最小堆:

所有的父節點必須小於它的兩個子節點

 

 

堆排序:

算法:一個列表是待排序的

構造最大(小)堆:

最大堆的規則:堆中所有的父節點必須都大於它的子節點

最大堆中的最大值是:根

最小堆的規則:堆中所有的父節點必須都小於它的子節點

最小堆中最小值是:根

 

排序:

假設使用最大堆

1生成一個空列表存儲排序后的結果

2將待排序的list構造成最大堆

3將最大堆的根元素放到空列表中,將剩余的元素通過下濾重新構造最大堆

4然后重復3的步驟,知道所有的元素都當過一次最大堆

 

拆解過程:

列表中的元素是排好序的,並且是降序的

result =[]

 

      5

   3    4

 1  2  

 

第一次:result:[5]

   3    4

 1  2

剩下的元素要構造新的最大堆

      4

    3

   1  2

第二次:result:[5,4]

    3

   1  2

再次構造最大堆

第三次:result:[5,4,3]

1 2

再次構造最大堆

  2

1

第三次:result:[5,4,3 ,2]

1

再次構造最大堆

第四次:result:[5,4,3,2,1]

完成了所有元素當過一次堆的根元素條件,結束堆排序

 

 

 

構造最大堆的時候,如何構造:

從堆的最下層開始構造,每構造一次進行一次上濾

將最大值向上傳遞。

下濾是從堆頂取值

 

代碼:

# encoding=utf-8

#左葉子、右葉子和父節點,三個元素,找到最大的一個

def maxHeap(heap,heapSize,i):#構造最大堆

    #參數heap為一個list,heapsize是指定這個list要操作的長度

    #i為某個節點,假設我們傳遞的是列表的倒數第三個元素

    #它的左節點坐標:2i

    #那么它的右節點坐標:2i + 1

    #它的父節點:i/2

   

    left = 2*i +1

    right = 2*i +2

    larger = i#當前節點的值

   

    #通過2次if的比較,將left、right和larger三者的最大值找到

    #然后將最大值所在的坐標賦值給larger

    if left < heapSize and heap[larger] < heap[left]:

        larger = left

 

    if right < heapSize and heap[larger] < heap[right]:

        larger = right

    #以上兩步是把三個節點中,最大的值的坐標給了larger

 

    #如果lager的值不是i,說明i的值需要和最大值進行交換

    #因為i的坐標是最大堆的堆頂,所以必須是最大值

    #如果不是i最大,則說明左結點,或者右節點最大,交換值

    #后,說明下面的堆有可能需要進行調整,所以通過遞歸來

    #建立左(右)結點下的最大堆。

    #如果最大值就是i,沒有進行交換值,所以不需要進行建立

    #左(右)結點下的最大堆,這是因為

    #做交換,如果最大值的坐標不是當前節點的坐標,說明更大的是左右節點之一

    #就把最大那個和當前節點做一個交換,這樣最大的就跑到上邊去了

    if larger != i:

        heap[i],heap[larger] = heap[larger],heap[i]

        maxHeap(heap,heapSize,larger)#遞歸調用larger是左節點坐標或者右節點坐標,繼續去找下邊的最大值,做交換

    #如果發生了larger =i 的情況,則次函數調用結束

    #以上步驟完成,堆頂坐標為i坐標的最大子堆建立好了

   

 

def buildMaxHeap(heap):

    #heap參數是未排序、未建堆的list

    heapSize = len(heap)

    #堆的長度//2可以找到堆里面的

    #最后一個帶有子節點的節點

    #循環可以實現從堆的最下層節點開始建堆

    #每次建立的堆都是一個最大堆

    #簡單來說把所有字段都建成最大堆

    #然后組成了最終的最大堆

    for i in range((heapSize-1)//2 -1,-1,-1):

        maxHeap(heap,heapSize,i)

    #(heapSize-1)//2是算出來當前堆中最后一個含有子節點的坐標

'''

      5

   3      4

 2   1  -1

'''

 

 

def heapSort(heap):

    #先把所有元素先建立一個最大堆

    buildMaxHeap(heap)

 

    #將堆中所有的元素都遍歷一遍

    #讓每個元素都做一次堆頂

    #然后將堆頂的每個元素都換到堆的最后一個節點

    for i in range(len(heap)-1,-1,-1):

        heap[0],heap[i] = heap[i],heap[0]

        #maxheap中的i是列表的長度,這樣可以防止追加到

        #堆后面的元素重新被當做最大堆元素進行建隊

        maxHeap(heap,i,0)

 

    return heap

    #第一次循環的時候,把最大值放到了列表最后面

    #把最后一個值(肯定不是最大值)放到了堆頂,然后把不包含最后一個元素的

    #剩余元素,重新進行最大堆排序

    #第二次循環的時候,把堆頂(次大值)放到列表倒數的第二個位置,然后把不包含最后

    #兩個元素的剩余元素,重新進行建立最大堆

    #。。。。

    #循環結束,那么列表的數據就排好了

 

   

 

if __name__ == '__main__':

    heap1 = [3,4,5,6,23,4,1,1,23,45,6678]

    print (heap1)

    heapSort(heap1)

    print (heap1)

 

 

算法:

將一個未排序的list,做成最大堆

buildMaxHeap函數通過maxHeap函數構造了最大堆

 

第一次從最大堆取出的元素和列表的最后一個的元素交換

位置,我們就找到了最大值

剩余的元素,進行新的最大堆建立

 

第二次從新建的最大堆堆頂取出來最大值,這個值和

列表中的倒數第二個數進行交換,那么第二大的值就找到了,

此時,最大值在列表的最后,第二大值在列表的倒數

第二個元素

 

第三次。。。。。重復上面的過程

直到所有的元素都被交換過一次位置

 

剛才有一個地方講解有偏差

maxHeap 這個函數的交換邏輯,應該是既不算上濾,也不算下濾

上濾:新插入元素和父節點比對,發生交換。下濾:左右節點比對后發生交換

maxHeap 這個函數的交換邏輯是三個數找到最大的,和上濾下濾還是有一些區別。

 

for i in range((heapSize-1)//2,-1,-1):
        maxHeap(heap,heapSize,i) 
這個循環要理解一下:

這個循環調用,表示從最下層的子樹,開始實現最大堆,這個就是我剛才說的從最下層開始建立最大堆的過程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM