堆排序是利用最大最或最小堆,廢話不多說:
先給出幾個概念:
二叉樹:二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”
完全二叉樹:除最后一層外,每一層上的節點數均達到最大值;在最后一層上只缺少右邊的若干結點。
滿二叉樹: 除最后一層無任何子節點外,每一層上的所有結點都有兩個子結點。
堆:堆是一種數據結構,類似樹根結構,如圖,但是不一定是二叉樹。
二叉堆:二叉堆是一種特殊的堆,二叉堆是完全二元樹(二叉樹)或者是近似完全二元樹(二叉樹),包括最大堆和最小堆。
最大堆:父結點的鍵值總是大於或等於任何一個子節點的鍵值,即根節點為最大數字
最小堆:父結點的鍵值總是大於或等於任何一個子節點的鍵值,即根節點為最小數字
堆排序步驟:
1.將數據構建成堆,這里的堆指完全二叉樹(不一定是滿二叉樹)
2.將堆調整為最小堆或最大堆
3.此時堆頂已經為最大數或最小數,可以對下面的分支堆再進行調堆即可,此處采用的是將堆頂數取出,再調堆
本人愚鈍,網上代碼不慎明了,根據自己的思路寫了一下,不足之處,請多多指教
1.首先實現將數組按照堆打印
1 def PrintArrayTree(arr): 2 frontRowSum=1 #Number of digits in front of n-1 rows 3 row=1 #row n(start from 1) 4 for i in range(0,len(arr)): 5 if i==frontRowSum: 6 frontRowSum=frontRowSum+2**row #Number of digits in front of n rows 7 print("\n")#the next row 8 row=row+1 9 print (arr[i],end=" ") #print digits 10 print("Over") 11 12 arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] 13 PrintArrayTree(arr)
運行結果如下:
10
9 8
7 6 5 4
3 2 1 234 562 452 23623 565
5 26
print Over
2.構建完了堆,我想實現在堆內任意查找,找到他的子節點和父節點,代碼如下:
1 def FindNode(arr,row,cloumn): 2 3 if row<1 or cloumn<1: 4 print("the number of row and column must be greater than 1") 5 return 6 if cloumn>2**(row-1): 7 print("this row just ",2**(row-1),"numbers") 8 return 9 10 frontRowSum=0 11 CurrentRowSum=0 12 for index in range(0,row-1): 13 CurrentRowSum=2**index #the number of digits in current row 14 frontRowSum=frontRowSum+CurrentRowSum #the number of digits of all rows 15 NodeIndex=frontRowSum+cloumn-1 #find the location of the node in the array by row and cloumn 16 17 if NodeIndex>len(arr)-1: 18 print("out of this array") 19 return 20 21 currentNode=arr[NodeIndex] 22 23 childIndex=NodeIndex*2+1 24 25 print("Current Node:",currentNode) 26 27 if row==1: #row 1 have no parent node 28 print("no parent node!") 29 else: #the parent node ofcurrent node 30 parentIndex=int((NodeIndex-1)/2) 31 parentNode=arr[parentIndex] 32 print("Parent Node:",parentNode) 33 34 if childIndex+1>len(arr): #print leftChild node 35 print("no left child node!") 36 else: 37 leftChild=arr[childIndex] 38 print("Left Child Node:",leftChild) 39 40 41 if childIndex+1+1>len(arr): #print rightChild node 42 print("no left right node!") 43 else: 44 rightChild=arr[childIndex+1] 45 print("Right Child Node:",rightChild) 46 47 print("\n") 48 49 arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] 50 FindNode(arr,1,1) 51 FindNode(arr,2,2) 52 FindNode(arr,4,1)
代碼運行結果如下:
Current Node: 10
no parent node!
Left Child Node: 9
Right Child Node: 8
Current Node: 8
Parent Node: 10
Left Child Node: 5
Right Child Node: 4
Current Node: 3
Parent Node: 7
Left Child Node: 5
Right Child Node: 26
此代碼在堆排序中沒有直接用到,但是提供了一些思路
3.按照堆排序步驟,建堆之后需要進行堆調整,接下來進行堆調整,先實現單個叉(某個節點及其子孩子)的進行排序,直接借鑒FindNode里面的代碼,將當前節點分別與其左右孩子比較就行了,本文意在實現最小堆,即將小的節點作為父節點
def MinSort(arr,row,cloumn): if row<1 or cloumn<1: print("the number of row and column must be greater than 1") return if cloumn>2**(row-1): print("this row just ",2**(row-1),"numbers") return frontRowSum=0 CurrentRowSum=0 for index in range(0,row-1): CurrentRowSum=2**index #the number of digits in current row frontRowSum=frontRowSum+CurrentRowSum #the number of digits of all rows NodeIndex=frontRowSum+cloumn-1 #find the location of the node in the array by row and cloumn if NodeIndex>len(arr)-1: print("out of this array") return currentNode=arr[NodeIndex] childIndex=NodeIndex*2+1 print("Current Node:",currentNode) if row==1: print("no parent node!") else: parentIndex=int((NodeIndex-1)/2) parentNode=arr[parentIndex] print("Parent Node:",parentNode) if childIndex+1>len(arr): print("no left child node!") else: leftChild=arr[childIndex] print("Left Child Node:",leftChild) if currentNode>leftChild: print("swap currentNode and leftChild") temp=currentNode currentNode=leftChild leftChild=temp arr[childIndex]=leftChild if childIndex+1>=len(arr): print("no right child node!") else: rightChild=arr[childIndex+1] print("Right Chile Node:",rightChild) if currentNode>rightChild: print("swap rightCild and leftChild") temp=rightChild rightChild=currentNode currentNode=temp arr[childIndex+1]=rightChild arr[NodeIndex]=currentNode arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] print("initial array:",arr) MinSort(arr,1,1) print("result array:",arr)
運行結果如下,可以看出對於第一個節點,其自孩子為9,8,已經實現將節點與最小的自孩子進行交換,保證父節點小於任何一個子孩子
initial array: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 234, 562, 452, 23623, 565, 5, 26]
Current Node: 10
no parent node!
Left Child Node: 9
swap currentNode and leftChild
Right Chile Node: 8
swap rightCild and leftChild
result array: [8, 10, 9, 7, 6, 5, 4, 3, 2, 1, 234, 562, 452, 23623, 565, 5, 26]
4.已經實現對單個節點和子孩子進行比較,保證父節點小於孩子,將堆內所有擁有孩子的節點進行排序,即可調整為最小堆,代碼如下:
def MinHeap(arr): frontRowSum=1 row=1 for i in range(0,len(arr)): if i==frontRowSum: frontRowSum=frontRowSum+2**row #the number of digits of all rows print("\n") # next row row=row+1 print (arr[i],end=" ") print("row",row) rowIndex=row-1 #the last row have no child node print("rowIndex",rowIndex) column=2**(rowIndex-1) #the number of digits of current row print("column",column) number=len(arr) while rowIndex>0: #sort the nodes that have child nodes from the last number to the first number if number<=2**(rowIndex-1): rowIndex=rowIndex-1 column=2**(rowIndex-1) print("sort",rowIndex,column) MinSort(arr,rowIndex,column) number=number-1 column=column-1 arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] print("initial array:",arr)
PrintArrayTree(arr) MinHeap(arr) print("result array:",arr)
PrintArrayTree(arr)
運行結果如下,可以看到最小數字已經位於頂端,實現最小堆
initial array: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 234, 562, 452, 23623, 565, 5, 26]
10
9 8
7 6 5 4
3 2 1 234 562 452 23623 565
5 26
print Over
.......
result array: [1, 10, 4, 9, 2, 8, 5, 7, 3, 6, 234, 562, 452, 23623, 565, 5, 26]
1
10 4
9 2 8 5
7 3 6 234 562 452 23623 565
5 26
print Over
4.最小值已經到頂端,將最小值依次取出,然后再調整堆,再取出,就完成堆排序。代碼如下:
1 def HeapSort(arr): 2 arr2=[] 3 for i in range(0,len(arr)): 4 MinHeap(arr) 5 arr2.append(arr[0]) 6 del arr[0] 7 return arr2 8 9 arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] 10 print("initial array:",arr) 11 PrintArrayTree(arr) 12 resultArr=HeapSort(arr) 13 print("result array:",resultArr) 14 PrintArrayTree(resultArr)
運行結果如下:
initial array: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 234, 562, 452, 23623, 565, 5, 26]
10
9 8
7 6 5 4
3 2 1 234 562 452 23623 565
5 26
print Over
10
9 8
7 6 5 4
3 2 1 234 562 452 23623 565
5 26
.........
result array: [1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 26, 234, 452, 562, 565, 23623]
1
2 3
4 5 5 6
7 8 9 10 26 234 452 562
565 23623
print Over
5.后續工作:
1)代碼需要優化
2)感覺堆排序有點類似冒泡排序
3)需要檢查代碼的健壯性
4)后續需要計算分析代碼的復雜度
1)優化之后的程序如下:寫法還能再優化,但繼續優化會影響可讀性
1 def MinSort(arr,start,end): 2 import math 3 arrHeight=0 4 for index in range(0,end-start): 5 if index==2**(arrHeight+1)-1: 6 arrHeight=arrHeight+1 7 8 for NodeIndex in range(2**(arrHeight)-2,-1,-1): 9 currentNode=arr[NodeIndex+start] 10 childIndex=NodeIndex*2+1+start 11 12 if childIndex+1>len(arr): 13 continue 14 else: 15 leftChild=arr[childIndex] 16 17 if currentNode>leftChild: 18 temp=currentNode 19 currentNode=leftChild 20 leftChild=temp 21 arr[childIndex]=leftChild 22 arr[NodeIndex+start]=currentNode 23 24 if childIndex+1>=len(arr): 25 continue 26 else: 27 rightChild=arr[childIndex+1] 28 if currentNode>rightChild: 29 30 temp=rightChild 31 rightChild=currentNode 32 currentNode=temp 33 arr[childIndex+1]=rightChild 34 arr[NodeIndex+start]=currentNode 35 36 37 def HeapSort(arr): 38 for i in range(0,len(arr)-1): 39 MinSort(arr,i,len(arr)) 40 41 42 arr=[10,9,8,7,6,5,4,3,2,1,234,562,452,23623,565,5,26] 43 44 print("Initial array:\n",arr) 45 HeapSort(arr) 46 print("Result array:\n",arr)
運行結果:
Initial array:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 234, 562, 452, 23623, 565, 5, 26]
Result array:
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 26, 234, 452, 562, 565, 23623]