前言:只有自己取亲自尝试,才知道坑有多少,一个细节没注意,都会导致整个结果的错误,泪奔。
' 堆排序
Sub main()
Dim a() As Variant
a = Array(1, 5, 2, 5, 0, 4, 8)
heapSort a
End Sub
' 封闭了数组操作,可以很安全的从1 开始
Sub heapSort(a() As Variant)
Dim i As Integer
Dim num As Integer
' 数组长度为num,从1-num
num = UBound(a) + 1
' 构建堆有序,升序,需要采用删除的方式,所以,需要寻找最大数值放于末尾,构建最大堆,
' 我们总是把根节点和尾节点交换,并让根节点再次下沉,以此来进行排序
For i = Int(num / 2) To 1 Step -1
sink a, i, num
Next
Dim k As Integer
k = num
' 使用删除的方式,来排序,尾部已经确认,所以不参与
' 为什么=1不参与排序?
' k = 1 已经越界了
While k > 1
exch a, 1, k
k = k - 1
sink a, 1, k
Wend
End Sub
Sub sink(a() As Variant, n As Integer, num As Integer)
' 准备下沉位置
Dim j As Integer
' 当前索引
Dim i As Integer
i = n
While i <= Int(num / 2)
' 注意,如果i=0,是会陷入死循环的,这是一个坑
j = 2 * i
' 防止越界,所以才做判断,如果 j = num ,依然可以比较并交换
If j < num Then
' 如果有两个节点,就可以这么操作,如果没有,这个步骤就可以省略了
' 这里关注更大,要满足稳定状态,两个子节点都比自身小,和更大的交换,才能稳定
' 取决于根节点的选取
If less(a, j, j + 1) Then j = j + 1
End If
' 注意,即使j=num,依然可以比较并交换,不要写入上面if
' 检查是否稳定,如果自身比最大的还大或者相等,状态已经稳定
If not less(a, i, j) Then Exit Sub
exch a, j, i
i = j
Wend
End Sub
' ----------封闭数组操作,可以隔离索引关系,比如数组是0 - 9,外层操作可以改为1-10 ,更加直观,方便----------
Private Function less(a() As Variant, i As Integer, j As Integer)
less = a(i - 1) < a(j - 1)
End Function
Sub exch(a() As Variant, i As Integer, j As Integer)
Dim temp
temp = a(i - 1)
a(i - 1) = a(j - 1)
a(j - 1) = temp
End Sub