zoukankan      html  css  js  c++  java
  • 堆排序(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("
    ")#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("
    ")
    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("
    ") # 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:
    ",arr)
    45 HeapSort(arr)
    46 print("Result array:
    ",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]

  • 相关阅读:
    MYSQL 数据库管理
    maven初学总结
    解决问题的思路
    java泛型综述
    几种不常用的排序算法
    创新思维
    Django从入门到放弃
    KlayGE 4.0中Deferred Rendering的改进(二):拥挤的GBuffer
    用Android NDK r6编译boost 1.47
    glloader移植到了Android
  • 原文地址:https://www.cnblogs.com/feichangnice/p/5321351.html
Copyright © 2011-2022 走看看