用VBA实现对一维数组的排序(7)堆排序

想要学习堆排序,就先的了解一点二叉树和堆的基础,这里我们不讲概念,直接上图先看看堆和二叉树的样子,认识一下这俩结构.

通过图,我们一目了然,

 

这就是一个典型的二叉树结构,

 

上图左边是一格最小的二叉树结构,是完全二叉树一个顶点连接两个点或一个左边的点,顶点称为父节点,下面的称为子节点子节点必须先有左边才有右边或者只有左边,如此才成为完全二叉树,,否则就是非完全二叉树,在堆排序中,我们不能出现非完全二叉树

那什么是堆呢?

当一个完全二叉树的父节点大于(大根堆)或小于(小根堆)该最小完全二叉树的所有子节点的时候,我们将其称为堆,堆,从宏观来看,顶端永远是最值,如果每次我们都将这个最值拿出来,再将剩下的数据调成堆,就又能找到剩余数据中的最值,这个动作是不是有点熟悉?没错这组动作恰好就是排序.我们看图,看图比文字更为直观,能更快的理解

第一步,将数据摆成一个二叉树,实际上二叉树和堆是不存在的,是人为的赋予的一种关系,

第二步,将二叉树转换为堆

 

 

 

 

 

 

 

 

 

这是大神写的一维数组的升序的代码,注释一应俱全

***********************************************************

Public Sub HeapSortFunction升(arr)

  iLength = UBound(arr)

  Call BuildMaxHeap升(arr, iLength) ' 创建大顶推(初始状态看做:整体无序)

  For i = iLength To 1 Step -1

  Call Swap(arr(0), arr(i), 0, i) ' 将堆顶元素依次与无序区的最后一位交换(使堆顶元素进入有序区)

  Call MaxHeapify升(arr, 0, i) '重新将无序区调整为大顶堆

  Next i

End Sub

' 创建大顶推(根节点大于左右子节点)

Private Sub BuildMaxHeap升(arr, iLength)

  '根据大顶堆的性质可知:数组的前半段的元素为根节点,其余元素都为叶节点

  For i = iLength \ 2 To 0 Step -1  '从最底层的最后一个根节点开始进行大顶推的调整

  Call MaxHeapify升(arr, i, iLength + 1) '调整大顶堆

  Next i

End Sub

Private Sub MaxHeapify升(arr, currentIndex, heapSize)

  Dim left As Long

  Dim right As Long

  Dim large As Long

  left = 2 * currentIndex + 1   '左子节点在数组中的位置

  right = 2 * currentIndex + 2  '右子节点在数组中的位置

  large = currentIndex      '记录此根节点左子节点右子节点 三者中最大值的位置

  If left < heapSize Then

  If arr(left) > arr(large) Then '与左子节点进行比较

    large = left

  End If

  End If

  If right < heapSize Then

  If arr(right) > arr(large) Then '与右子节点进行比较

    large = right ';

  End If

  End If

  If currentIndex <> large Then '如果 currentIndex不等于large 则表明 large 发生变化(即:左右子节点中有大于根节点的情况)

  Call Swap(arr(currentIndex), arr(large), currentIndex, large) '将左右节点中的大者与根节点进行交换(即:实现局部大顶堆)

  Call MaxHeapify升(arr, large, heapSize) '以上次调整动作的large位置(为此次调整的根节点位置),进行递归调整

  End If

End Sub

Private Sub Swap(a, b, n1, n2)

    Dim temp As Long

    temp = a

    a = b

    b = temp

End Sub

Function 一维数组排序升序测试()

arr = Array(2, 50, 20, 6, 1, 0, 8, 4, 9, 3, 7, 22, 33, 5)

HeapSortFunction升 arr

End Function

***********************************************************

这是我修改后调用了他的代码写的二维数组多列自由升序降序的代码

***********************************************************

Public Function HeapSortFunction升(Myarr, 起始, 终止)

ReDim arr(0 To 终止 - 起始)

For t = 起始 To 终止

arr(t - 起始) = Myarr(t)

Next

  iLength = UBound(arr)

  Call BuildMaxHeap升(arr, iLength)

  For i = iLength To 1 Step -1

  Call Swap(arr(0), arr(i), 0, i)

  Call MaxHeapify升(arr, 0, i)

  Next i

For t = 起始 To 终止

Myarr(t) = arr(t - 起始)

Next

HeapSortFunction升 = Myarr

End Function

Private Sub BuildMaxHeap升(arr, iLength)

  For i = iLength \ 2 To 0 Step -1

  Call MaxHeapify升(arr, i, iLength + 1)

  Next i

End Sub

Private Sub MaxHeapify升(arr, currentIndex, heapSize)

  Dim left As Long

  Dim right As Long

  Dim large As Long

  left = 2 * currentIndex + 1

  right = 2 * currentIndex + 2

  large = currentIndex

  If left < heapSize Then

  If arr(left) > arr(large) Then

    large = left

  End If

  End If

  If right < heapSize Then

  If arr(right) > arr(large) Then

    large = right

  End If

  End If

  If currentIndex <> large Then

  Call Swap(arr(currentIndex), arr(large), currentIndex, large)

  Call MaxHeapify升(arr, large, heapSize)

  End If

End Sub

Public Function HeapSortFunction降(Myarr, 起始, 终止)

ReDim arr(0 To 终止 - 起始)

For t = 起始 To 终止

arr(t - 起始) = Myarr(t)

Next

  iLength = UBound(arr)

  Call BuildMaxHeap降(arr, iLength)

  For i = iLength To 1 Step -1

  Call Swap(arr(0), arr(i), 0, i)

  Call MaxHeapify降(arr, 0, i)

  Next i

For t = 起始 To 终止

Myarr(t) = arr(t - 起始)

Next

HeapSortFunction降 = Myarr

End Function

Private Sub BuildMaxHeap降(arr, iLength)

  For i = iLength \ 2 To 0 Step -1

  Call MaxHeapify降(arr, i, iLength + 1)

  Next i

End Sub

Private Sub MaxHeapify降(arr, currentIndex, heapSize)

  Dim left As Long

  Dim right As Long

  Dim large As Long

  left = 2 * currentIndex + 1

  right = 2 * currentIndex + 2

  large = currentIndex

  If left < heapSize Then

  If arr(left) < arr(large) Then

    large = left

  End If

  End If

  If right < heapSize Then

  If arr(right) < arr(large) Then

    large = right

  End If

  End If

  If currentIndex <> large Then

  Call Swap(arr(currentIndex), arr(large), currentIndex, large)

  Call MaxHeapify降(arr, large, heapSize)

  End If

End Sub

Private Sub Swap(a, b, n1, n2)

    Dim temp As Long

    temp = a

    a = b

    b = temp

End Sub

Private Function 行号记录字典(ALL, 值列, 数组索引起点, 数组索引终点, Optional 功能 = 0)

Dim Dic

    Set Dic = CreateObject("Scripting.Dictionary")

    For i = 数组索引起点 To 数组索引终点

        key = ALL(i, 值列)

        If Dic.Exists(key) = False Then

            Dic(key) = i

        Else

            Dic(key) = Dic(key) & "=*=" & i

        End If

    Next

    If 功能 = 0 Then

        行号记录字典 = Dic.Keys

    ElseIf 功能 = 1 Then

        行号记录字典 = Dic.Items

    Else

        Set 行号记录字典 = Dic

    End If

End Function

Private Function 单列堆排序模块(arr, 值列, 起点, 终点)

Dim 升降 As Boolean

If 值列 < 0 Then

    值列 = Abs(值列)

    升降 = False

ElseIf 值列 > 0 Then

    值列 = Abs(值列)

    升降 = True

End If

ReDim arr_son(起点 To 终点, LBound(arr, 2) To UBound(arr, 2))

Set Dic = 行号记录字典(arr, 值列, 起点, 终点, 3)

    arr_rows = Dic.Keys

    If 升降 = True Then

        arr_rows = HeapSortFunction升(arr_rows, LBound(arr_rows), UBound(arr_rows))

    Else

        arr_rows = HeapSortFunction降(arr_rows, LBound(arr_rows), UBound(arr_rows))

    End If

ReDim brr(LBound(arr_rows) To UBound(arr_rows))

    For i = LBound(arr_rows) To UBound(arr_rows)

        brr(i) = Dic(arr_rows(i))

    Next

    g = 起点

    For i = LBound(brr) To UBound(brr)

        crr = Split(brr(i), "=*=")

        For t = LBound(crr) To UBound(crr)

            For h = LBound(arr, 2) To UBound(arr, 2)

                arr_son(g, h) = arr(Abs(crr(t)), h)

            Next

            g = g + 1

        Next

    Next

    For i = 起点 To 终点

        For t = LBound(arr, 2) To UBound(arr, 2)

            arr(i, t) = arr_son(i, t)

        Next

    Next

End Function

Private Function 多列堆排序模块(arr, 值列串, 起点, 终点, Optional 递推 = 0)

    arr_值组 = Split(值列串, ",")

    s = UBound(arr_值组)

    If 递推 > s Then Exit Function

    If 递推 > 8 Then Exit Function

    单列堆排序模块 arr, Val(arr_值组(递推)), 起点, 终点

    brr = 行号记录字典(arr, Abs(arr_值组(递推)), 起点, 终点, 1)

    For t = LBound(brr) To UBound(brr)

        crr = Split(brr(t), "=*=")

        If UBound(crr) > 0 Then

            多列堆排序模块 arr, 值列串, crr(LBound(crr)), crr(UBound(crr)), 递推 + 1

        End If

    Next

End Function

Sub 多列归并测试()

arr = Sheet6.Range("a1:g52")

多列堆排序模块 arr, "+4,-5,+6,-7", 3, 52

Sheet6.Range("i1").Resize(52, 7) = arr

End Sub

***********************************************************

函数用法:

多列堆排序模块(arr, 值列串, 起点, 终点, Optional 递推 = 0)

arr:指需要排除的二维数组

值列串:指排序的主列,和次列数据串,以"+4,-5,+6,-7"这样的形式输入,”+”代表升序,”-”代表降序. "+4,-5,+6,-7"就是4列为主列升序,5,7为降序次列,6为升序次列.

起点: 二维数组arr需要排序部分的起始行

终点: 二维数组arr需要排序部分的终止行

多列堆排序模块最后输出一个数组就是就是排好序的数组.

关于一维数组如何升级为二维数组多列自由升序降序的过程,另有文章,可移步参考.

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值