2020-05-21 22:27:25 +08:00
|
|
|
|
#Region "Microsoft.VisualBasic::2b9b4477aab4d6daf2a1ba32be42498b, Microsoft.VisualBasic.Core\ComponentModel\System.Collections.Generic\BinaryHeap.vb"
|
2019-08-11 12:22:38 +08:00
|
|
|
|
|
|
|
|
|
|
' Author:
|
|
|
|
|
|
'
|
|
|
|
|
|
' asuka (amethyst.asuka@gcmodeller.org)
|
|
|
|
|
|
' xie (genetics@smrucc.org)
|
|
|
|
|
|
' xieguigang (xie.guigang@live.com)
|
|
|
|
|
|
'
|
|
|
|
|
|
' Copyright (c) 2018 GPL3 Licensed
|
|
|
|
|
|
'
|
|
|
|
|
|
'
|
|
|
|
|
|
' GNU GENERAL PUBLIC LICENSE (GPL3)
|
|
|
|
|
|
'
|
|
|
|
|
|
'
|
|
|
|
|
|
' This program is free software: you can redistribute it and/or modify
|
|
|
|
|
|
' it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
' the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
|
' (at your option) any later version.
|
|
|
|
|
|
'
|
|
|
|
|
|
' This program is distributed in the hope that it will be useful,
|
|
|
|
|
|
' but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
' GNU General Public License for more details.
|
|
|
|
|
|
'
|
|
|
|
|
|
' You should have received a copy of the GNU General Public License
|
|
|
|
|
|
' along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
' /********************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
' Summaries:
|
|
|
|
|
|
|
|
|
|
|
|
' Class BinaryHeap
|
|
|
|
|
|
'
|
|
|
|
|
|
' Properties: peek, size
|
|
|
|
|
|
'
|
|
|
|
|
|
' Constructor: (+1 Overloads) Sub New
|
|
|
|
|
|
'
|
|
|
|
|
|
' Function: pop
|
|
|
|
|
|
'
|
|
|
|
|
|
' Sub: bubbleUp, push, remove, sinkDown
|
|
|
|
|
|
'
|
|
|
|
|
|
'
|
|
|
|
|
|
' /********************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#End Region
|
|
|
|
|
|
|
|
|
|
|
|
Imports Microsoft.VisualBasic.Language
|
2020-04-17 18:31:10 +08:00
|
|
|
|
Imports stdNum = System.Math
|
2019-08-10 01:31:53 +08:00
|
|
|
|
|
|
|
|
|
|
Namespace ComponentModel.Collection
|
|
|
|
|
|
|
|
|
|
|
|
''' <summary>
|
|
|
|
|
|
''' Binary heap implementation from:
|
|
|
|
|
|
'''
|
|
|
|
|
|
''' > http://eloquentjavascript.net/appendix2.html
|
|
|
|
|
|
''' </summary>
|
|
|
|
|
|
''' <typeparam name="T"></typeparam>
|
|
|
|
|
|
Public Class BinaryHeap(Of T As Class)
|
|
|
|
|
|
|
|
|
|
|
|
ReadOnly content As New List(Of T)
|
|
|
|
|
|
ReadOnly scoreFunction As Func(Of T, Double)
|
|
|
|
|
|
|
|
|
|
|
|
Public ReadOnly Property size As Integer
|
|
|
|
|
|
Get
|
|
|
|
|
|
Return content.Count
|
|
|
|
|
|
End Get
|
|
|
|
|
|
End Property
|
|
|
|
|
|
|
|
|
|
|
|
Default Public ReadOnly Property Item(i As Integer) As T
|
|
|
|
|
|
Get
|
|
|
|
|
|
Return content(i)
|
|
|
|
|
|
End Get
|
|
|
|
|
|
End Property
|
|
|
|
|
|
|
|
|
|
|
|
Public ReadOnly Property peek As T
|
|
|
|
|
|
Get
|
|
|
|
|
|
Return content(Scan0)
|
|
|
|
|
|
End Get
|
|
|
|
|
|
End Property
|
|
|
|
|
|
|
|
|
|
|
|
Sub New(scoreFunction As Func(Of T, Double))
|
|
|
|
|
|
Me.scoreFunction = scoreFunction
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
|
|
|
|
|
|
Public Sub push(element As T)
|
|
|
|
|
|
' Add the new element to the end of the array.
|
|
|
|
|
|
' Then allow it to bubble up.
|
|
|
|
|
|
content.Add(element)
|
|
|
|
|
|
bubbleUp(content.Count - 1)
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
|
|
|
|
|
|
Public Function pop() As T
|
|
|
|
|
|
' Store the first element so we can return it later.
|
|
|
|
|
|
' Get the element at the end of the array.
|
|
|
|
|
|
Dim result = content(Scan0)
|
|
|
|
|
|
Dim [end] = content.Pop
|
|
|
|
|
|
|
|
|
|
|
|
' If there are any elements left, put the end element at the
|
|
|
|
|
|
' start, And let it sink down.
|
|
|
|
|
|
If content > 0 Then
|
|
|
|
|
|
content(Scan0) = [end]
|
|
|
|
|
|
sinkDown(Scan0)
|
|
|
|
|
|
End If
|
|
|
|
|
|
|
|
|
|
|
|
Return result
|
|
|
|
|
|
End Function
|
|
|
|
|
|
|
|
|
|
|
|
Public Sub remove(node As T)
|
|
|
|
|
|
Dim len = content.Count
|
|
|
|
|
|
Dim [end] As T
|
|
|
|
|
|
|
|
|
|
|
|
' To remove a value, we must search through the array to find
|
|
|
|
|
|
' it.
|
|
|
|
|
|
For i As Integer = 0 To len - 1
|
|
|
|
|
|
If content(i) Is node Then
|
|
|
|
|
|
' When it is found, the process seen in 'pop' is repeated
|
|
|
|
|
|
' to fill up the hole.
|
|
|
|
|
|
[end] = content.Pop
|
|
|
|
|
|
|
|
|
|
|
|
If i <> len - 1 Then
|
|
|
|
|
|
content(i) = [end]
|
|
|
|
|
|
|
|
|
|
|
|
If scoreFunction([end]) < scoreFunction(node) Then
|
|
|
|
|
|
bubbleUp(i)
|
|
|
|
|
|
Else
|
|
|
|
|
|
sinkDown(i)
|
|
|
|
|
|
End If
|
|
|
|
|
|
End If
|
|
|
|
|
|
|
|
|
|
|
|
Return
|
|
|
|
|
|
End If
|
|
|
|
|
|
Next
|
|
|
|
|
|
|
|
|
|
|
|
Throw New Exception("Node not found.")
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
|
|
|
|
|
|
Private Sub bubbleUp(n As Integer)
|
|
|
|
|
|
' Fetch the element that has to be moved.
|
|
|
|
|
|
Dim element = content(n)
|
|
|
|
|
|
|
|
|
|
|
|
' When at 0, an element can not go up any further.
|
|
|
|
|
|
Do While n > 0
|
|
|
|
|
|
' Compute the parent element's index, and fetch it.
|
2020-04-17 18:31:10 +08:00
|
|
|
|
Dim parentN% = stdNum.Floor((n + 1) / 2) - 1
|
2019-08-10 01:31:53 +08:00
|
|
|
|
Dim parent = content(parentN)
|
|
|
|
|
|
|
|
|
|
|
|
' Swap the elements if the parent is greater.
|
|
|
|
|
|
If scoreFunction(element) < scoreFunction(parent) Then
|
|
|
|
|
|
content(parentN) = element
|
|
|
|
|
|
content(n) = parent
|
|
|
|
|
|
' Update 'n' to continue at the new position.
|
|
|
|
|
|
n = parentN
|
|
|
|
|
|
Else
|
|
|
|
|
|
' Found a parent that is less, no need to move it further.
|
|
|
|
|
|
Exit Do
|
|
|
|
|
|
End If
|
|
|
|
|
|
Loop
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
|
|
|
|
|
|
Private Sub sinkDown(n As Integer)
|
|
|
|
|
|
' Look up the target element and its score.
|
|
|
|
|
|
Dim length = content.Count
|
|
|
|
|
|
Dim element = content(n)
|
|
|
|
|
|
Dim elemScore = scoreFunction(element)
|
|
|
|
|
|
Dim child1Score As Double
|
|
|
|
|
|
Dim child1 As T
|
|
|
|
|
|
|
|
|
|
|
|
Do While True
|
|
|
|
|
|
' Compute the indices of the child elements.
|
|
|
|
|
|
Dim child2N = (n + 1) * 2, child1N = child2N - 1
|
|
|
|
|
|
' This is used to store the new position of the element,
|
|
|
|
|
|
' if any.
|
|
|
|
|
|
Dim swap As Integer?
|
|
|
|
|
|
|
|
|
|
|
|
' If the first child exists (is inside the array)...
|
|
|
|
|
|
If (child1N < length) Then
|
|
|
|
|
|
' Look it up And compute its score.
|
|
|
|
|
|
child1 = content(child1N)
|
|
|
|
|
|
child1Score = scoreFunction(child1)
|
|
|
|
|
|
|
|
|
|
|
|
' If the score Is less than our element's, we need to swap.
|
|
|
|
|
|
If child1Score < elemScore Then
|
|
|
|
|
|
swap = child1N
|
|
|
|
|
|
End If
|
|
|
|
|
|
End If
|
|
|
|
|
|
|
|
|
|
|
|
' Do the same checks for the other child.
|
|
|
|
|
|
If child2N < length Then
|
|
|
|
|
|
Dim child2 = content(child2N)
|
|
|
|
|
|
Dim child2Score = scoreFunction(child2)
|
|
|
|
|
|
|
|
|
|
|
|
If (child2Score < If(swap Is Nothing, elemScore, child1Score)) Then
|
|
|
|
|
|
swap = child2N
|
|
|
|
|
|
End If
|
|
|
|
|
|
End If
|
|
|
|
|
|
|
|
|
|
|
|
' If the element needs to be moved, swap it, and continue.
|
|
|
|
|
|
If Not swap Is Nothing Then
|
|
|
|
|
|
content(n) = content(swap)
|
|
|
|
|
|
content(swap) = element
|
|
|
|
|
|
n = swap
|
|
|
|
|
|
Else
|
|
|
|
|
|
' Otherwise, we are done.
|
|
|
|
|
|
Exit Do
|
|
|
|
|
|
End If
|
|
|
|
|
|
Loop
|
|
|
|
|
|
End Sub
|
|
|
|
|
|
End Class
|
2019-08-11 12:22:38 +08:00
|
|
|
|
End Namespace
|