Binomial heapsΒΆ

A free binary tree container is defined according to

Object subclass: #CTBinomialHeap
	instanceVariableNames: 'representation'
	classVariableNames: ''
	package: 'Containers-BinomialHeap'

and its responsibility is to direct and manage objects of types

Object subclass: #CTBinomialTree
	instanceVariableNames: 'content children'
	classVariableNames: ''
	package: 'Containers-BinomialHeap'

as actual representation for the underlying structure. The simpler container is the empty tree,

../_images/CTBinomialHeapTest-testCreation.svg

where

"CTBinomialHeap class, protocol requirements"
empty

   ^ self new
        representation: nil;
        yourself

In general, we use collections and then build trees out of them. On one hand, using ArrayedCollection objects

../_images/CTBinomialHeapTest-testPushOrderedInterval.svg

where

"CTBinomialHeapTest, protocol tests"
tree: aCollection

   ^ aCollection asBinomialHeap
"Collection, protocol *Containers-BinomialHeap"
asBinomialHeap

   ^ self asBinaryTree: CTBinomialHeap

and

"CTBinomialHeap class, protocol instance creation"
withArrayedCollection: aCollection

   ^ aCollection ifEmpty: [ self empty ] ifNotEmpty: [ 
        self new yourself: [ :tree | 
           tree representation: (aCollection
                  bisect: [ :l :r | tree merge: l with: r ]
                  baseBlock: [ :each | 0 -> (CTBinomialTree leaf: each) ~~> nil ]) ] ]

uses

"CTBinomialHeap, protocol adding"
merge: trees with: otherTrees

   ^ trees ifNil: [ otherTrees ] ifNotNil: [ 
        otherTrees ifNil: [ trees ] ifNotNil: [ 
           | aTree anotherTree allButFirstTrees allButFirstOtherTrees aRank anotherRank |
           "Getting rests of both collections of trees to merge."
           allButFirstTrees := trees nextLink.
           allButFirstOtherTrees := otherTrees nextLink.

           "Getting current topmost trees."
           aTree := trees value.
           anotherTree := otherTrees value.

           "Getting ranks."
           aRank := aTree key.
           anotherRank := anotherTree key.

           "Rank comparison via `#key`."
           aRank < anotherRank
              ifTrue: [ 
              aTree ~~> (self merge: allButFirstTrees with: otherTrees) ]
              ifFalse: [ 
                 anotherRank < aRank
                    ifTrue: [ 
                    anotherTree
                    ~~> (self merge: trees with: allButFirstOtherTrees) ]
                    ifFalse: [ 
                       | binomialTree mergedTrees |
                       "Invariant: both `aTree` and `anotherTree` have the *same* rank."
                       binomialTree := aTree value linkBinomialTree:
                                          anotherTree value.
                       mergedTrees := self
                                         merge: allButFirstTrees
                                         with: allButFirstOtherTrees.
                       self pushTree: aRank + 1 -> binomialTree onTrees: mergedTrees ] ] ] ]

that delegates on both

"CTBinomialHeap, protocol adding"
pushTree: anAssociation onTrees: trees

   ^ trees ifNil: [ anAssociation ~~> trees ] ifNotNil: [ 
        | carAssociation rank |
        rank := anAssociation key.
        carAssociation := trees value.
        rank < carAssociation key
           ifTrue: [ anAssociation ~~> trees ]
           ifFalse: [ 
              self
                 pushTree: rank + 1
                    ->
                    (anAssociation value linkBinomialTree: carAssociation value)
                 onTrees: trees nextLink ] ]

and

"CTBinomialTree, protocol as yet unclassified"
linkBinomialTree: aTree

   | x |
   x := aTree content.
   ^ content < x
        ifTrue: [ self class node: content children: aTree ~~> children ]
        ifFalse: [ self class node: x children: self ~~> aTree children ]

to finally build the tree. On the other hand, using Collection objects

../_images/CTBinomialHeapTest-testPushOrderedCollection.svg

where

"CTBinomialHeap class, protocol instance creation"
withCollection: aCollection

   ^ aCollection
        inject: self empty
        into: [ :aBinaryTree :each | aBinaryTree push: each ]

uses

"CTBinomialHeap, protocol adding"
push: x

   representation := self
                        pushTree: 0 -> (CTBinomialTree leaf: x)
                        onTrees: representation

repeatedly. The two cases above can be redone with shuffled collections, both

../_images/CTBinomialHeapTest-testPushShuffledInterval.svg

and

../_images/CTBinomialHeapTest-testPushShuffledCollection.svg

respectively.