Python實現經典排序演算法 堆排序

2021-08-21 10:45:46 字數 4735 閱讀 3346

上次說到了經典演算法選擇排序,感覺是比較簡單的演算法,這一次說一說稍微有點難度的堆排序。

堆排序的時間複雜度要明顯優於前面的氣泡排序,插入排序和選擇排序(侷限於n較大時)。

先來講講堆(二叉堆),是乙個陣列,它可以近似被看作是乙個完全二叉樹。樹上每乙個節點對應乙個元素,除了最底層外,該樹是完全充滿的,而且是從左至右填充的,所有最底層的元素會從左向右填充。表示堆的陣列list包括兩個屬性,list.length表示陣列的個數,list.heap_size則表示有多少個堆元素儲存在該陣列中。也就是0<=list.heap_size<=list.length,list中可能存在若干個元素不是堆元素,在講堆性質的時候會舉例說明。

二叉堆有兩種形式,最大堆和最小堆,但其實本身性質是一樣的,就和從小到大排序和從大到小排序一樣。

最大堆性質是指除了根以外的所有節點,都要滿足:

list[parent(i)] >= list[i]

最小堆性質要滿足:

list[parent(i)] <= list[i]

如果把堆看作是一棵樹,堆高度就是指的堆中節點的高度,即為根節點到葉節點最長簡單路徑上的數目。

對於乙個元素數量為n的list,其堆高度為floor(lg n)。

下面來證明一下:在高度為h的堆中,元素最多的應該是當底層全滿時,即:1+2+2^2+……+2^h=2^(h+1)-1

元素最少的應該是當底層只有乙個元素時,即:1+2+……+2^(h-1)+1=2^h

則有:2^h<=n<=2^(h+1)-1,分別對不等式裡面取對數lg,既有lg(2^h)<=lg n<=lg(2^(h+1)-1),則有h<=lg n

其實堆排序就只有兩種過程,乙個是建堆,乙個是堆的維護,建堆的歷遍的過程,而維護則是遞迴的過程。在這裡維護是底層,而歷遍是頂層。我們先來看看維護,以求解最大堆為例,先定義乙個初始化的根節點,這裡我們選擇root=length//2,來作為初始化值,left=2*root(左結點),right=left+1(右結點),堆維護實質上就是通過不斷的交換順序來保證堆的性質。即判斷根結點與左結點、右結點的最大值,如果左結點的值最大,則與根結點交換位置,若是右結點的值最大,則與根結點交換位置,否則該結點即為根結點,左結點,右結點的最大值,傳遞根結點下標到下一次遞迴,直到找到list中的最大根結點。而頂層迴圈則是倒序歷遍lenth//2,這樣足以完成所有元素的呼叫,甚至可以為(length-2)//2,終止條件是當根結點的下標為0時,結點1已經為最大堆的根節點了,此時迴圈結束。但是到這一步還不夠,這一步僅僅是能確保下標為0的結點1為根結點,即只能確保list[0]為根節點,通過講該根節點與list[list.szie]進行互換,去掉根節點,形成乙個新堆,長度為length-=1,構造新堆後,在利用堆維護性質來獲取新堆的根節點,依次的我們可以結點提取出來,形成乙個序列,這就是我們要求的序列。以下是用python實現經典插入排序的code。這裡的時間複雜度為omiga(n*lg n)

def heapsort(list):

if list!=none:

if list==1:

pass

else:

for start in range((len(list))//2,-1,-1):#頂層迴圈第一步,找到堆的根結點

rootsort(list,start,len(list)-1)

for end in range(len(list)-1,-1,-1):#頂層迴圈第二步,講根結點依次提取並排序

list[0],list[end]=list[end],list[0]

end-=1

rootsort(list,0,end)

print (list)

def rootsort(list,root,end):#遞迴函式,對list做最大堆調整

left=2*root #父結點的左結點

right=left+1#父結點的右結點

if left<=end and list[root]

out:[1, 2, 4, 4, 7, 8, 9, 10, 14, 16]

上面過程可以用網路上的一張進行描述:

這裡我再詳細將每一次求根結點過程展示一下:

def heapsort(list):

if list!=none:

if list==1:

pass

else:

for start in range((len(list))//2,-1,-1):

print(start)

rootsort(list,start,len(list)-1)

for end in range(len(list)-1,-1,-1):

list[0],list[end]=list[end],list[0]

print ('*',end,'*')

print ('^',list,'^')

end-=1

rootsort(list,0,end)

print (list)

def rootsort(list,root,end):

left=2*root

right=left+1

if left<=end and list[root]out:

543" 3 "

[4, 1, 4, 14, 16, 9, 10, 2, 8, 7]

2" 2 "

[4, 1, 16, 14, 4, 9, 10, 2, 8, 7]

" 4 "

[4, 1, 16, 14, 8, 9, 10, 2, 4, 7]

1" 1 "

[4, 16, 1, 14, 8, 9, 10, 2, 4, 7]

" 2 "

[4, 16, 9, 14, 8, 1, 10, 2, 4, 7]

0" 0 "

[16, 4, 9, 14, 8, 1, 10, 2, 4, 7]

" 1 "

[16, 14, 9, 4, 8, 1, 10, 2, 4, 7]

" 3 "

[16, 14, 9, 10, 8, 1, 4, 2, 4, 7]

* 9 *

^ [7, 14, 9, 10, 8, 1, 4, 2, 4, 16] ^

" 0 "

[14, 7, 9, 10, 8, 1, 4, 2, 4, 16]

" 1 "

[14, 10, 9, 7, 8, 1, 4, 2, 4, 16]

* 8 *

^ [4, 10, 9, 7, 8, 1, 4, 2, 14, 16] ^

" 0 "

[10, 4, 9, 7, 8, 1, 4, 2, 14, 16]

" 1 "

[10, 9, 4, 7, 8, 1, 4, 2, 14, 16]

" 2 "

[10, 9, 8, 7, 4, 1, 4, 2, 14, 16]

* 7 *

^ [2, 9, 8, 7, 4, 1, 4, 10, 14, 16] ^

" 0 "

[9, 2, 8, 7, 4, 1, 4, 10, 14, 16]

" 1 "

[9, 8, 2, 7, 4, 1, 4, 10, 14, 16]

" 2 "

[9, 8, 4, 7, 2, 1, 4, 10, 14, 16]

* 6 *

^ [4, 8, 4, 7, 2, 1, 9, 10, 14, 16] ^

" 0 "

[8, 4, 4, 7, 2, 1, 9, 10, 14, 16]

" 1 "

[8, 7, 4, 4, 2, 1, 9, 10, 14, 16]

* 5 *

^ [1, 7, 4, 4, 2, 8, 9, 10, 14, 16] ^

" 0 "

[7, 1, 4, 4, 2, 8, 9, 10, 14, 16]

" 1 "

[7, 4, 1, 4, 2, 8, 9, 10, 14, 16]

" 2 "

[7, 4, 2, 4, 1, 8, 9, 10, 14, 16]

* 4 *

^ [1, 4, 2, 4, 7, 8, 9, 10, 14, 16] ^

" 0 "

[4, 1, 2, 4, 7, 8, 9, 10, 14, 16]

" 1 "

[4, 4, 2, 1, 7, 8, 9, 10, 14, 16]

* 3 *

^ [1, 4, 2, 4, 7, 8, 9, 10, 14, 16] ^

" 0 "

[4, 1, 2, 4, 7, 8, 9, 10, 14, 16]

" 1 "

[4, 2, 1, 4, 7, 8, 9, 10, 14, 16]

* 2 *

^ [1, 2, 4, 4, 7, 8, 9, 10, 14, 16] ^

" 0 "

[2, 1, 4, 4, 7, 8, 9, 10, 14, 16]

* 1 *

^ [1, 2, 4, 4, 7, 8, 9, 10, 14, 16] ^

* 0 *

^ [1, 2, 4, 4, 7, 8, 9, 10, 14, 16] ^

[1, 2, 4, 4, 7, 8, 9, 10, 14, 16]

Python實現經典排序演算法

import random lis list range 100 random.shuffle lis print lis def bubblesort arr for i in range 1 len arr for j in range 0 len arr i if arr j arr j 1 ...

Python 實現經典排序演算法

穩定的排序演算法 氣泡排序 插入排序 歸併排序和基數排序。不是穩定的排序演算法 選擇排序 快速排序 希爾排序 堆排序。a 80,15,45,35,88,46,55,66,22,99,0,1,100 for j in range 0,len a for i in range 0,len a 1 if ...

Python實現經典排序演算法 氣泡排序

1.氣泡排序概述 氣泡排序是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢 浮 到數列的頂端。2.演算法思想 比較相鄰...