堆排序(python實現)


 堆排序是利用最大最或最小堆,廢話不多說:

先給出幾個概念:

二叉樹:二叉樹是每個節點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(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]

 


免責聲明!

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



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