• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Collection] Tree

Status
Not open for further replies.
new thread

Still writing examples on how to iterate over the tree, but this is a standard tree.

How it works?

All nodes within the tree are trees themselves. A tree has a queue of children implemented as a list (this is so that any child can be arbitrarily removed). To remove a child, that child is destroyed.

From what I'm seeing so far, a Tree must be Shared and can only be either Shared or SharedNxUnique. There is also no point to having a static tree.

So far, I've written the breadth-first search algorithm for this ;). I plan to write all of the others up too.

JASS:
library Tree /* v1.0.0.0
************************************************************************************
*
*   */uses/*
*   
*       */ ErrorMessage /*         hiveworkshop.com/forums/submissions-414/snippet-error-message-239210/
*
************************************************************************************
*
*   module Tree
*
*       Description
*       -------------------------
*
*           Trees and nodes are the same
*
*       Fields
*       -------------------------
*
*           readonly static integer sentinel
*
*           readonly thistype root
*           readonly thistype children
*
*           readonly thistype next
*
*       Methods
*       -------------------------
*
*           static method create takes nothing returns thistype
*           method destroy takes nothing returns nothing
*
*           method clear takes nothing returns nothing
*
*           method insert takes nothing returns thistype
*
*           debug static method calculateMemoryUsage takes nothing returns integer
*           debug static method getAllocatedMemoryAsString takes nothing returns string
*
*       Examples
*       -------------------------
*
*           Breadth-First (level by level)
*
*               local UniqueQueue queue = UniqueQueue.create()
*               local UniqueQueue children
*
*               local thistype node = this.children
*               local UniqueQueue child
*
*               //first put into queue
*               loop
*                   exitwhen node == 0
*
*                   call queue.enqueue(node)
*
*                   set node = node.next
*               endloop
*
*               //loop until there are no children
*               loop
*                   set child = queue.first
*                   exitwhen child == 0
*
*                   //create a queue to store the next level's children
*                   set children = UniqueQueue.create()
*
*                   //loop over all children of current level
*                   loop
*                       set node = thistype(child).children
*
*                       //
*                       //  Put Code Here
*                       //
*               
*                       //loop over all children of current child
*                       loop
*                           exitwhen node == 0
*
*                           //now on next level, put next level's node into queue
*                           call children.enqueue(node)
*
*                           set node = node.next
*                       endloop
*
*                       set child = child.next
*                       exitwhen child == 0
*                   endloop
*
*                   //go to next level
*                   call queue.destroy()
*                   set queue = children
*               endloop
*
*               call queue.destroy()
*
*           Depth-First (bottom up)
*
*               
*
*           In-Order (left to right)
*
*               
*
*           Post-Order (right to left)
*
*               
*
************************************************************************************/
    module Tree
        /*
        *   All nodes within a tree are collections
        */
        private static thistype collectionCount = 0
        debug private boolean isCollection
        
        private thistype _root
        method operator root takes nothing returns thistype
            debug call ThrowError(this == 0,        "Tree", "root", "thistype", this, "Attempted To Read Null Node.")
            debug call ThrowError(not isCollection, "Tree", "root", "thistype", this, "Attempted To Read Invalid Node.")
            
            return _root
        endmethod
        
        private thistype _next
        method operator next takes nothing returns thistype
            debug call ThrowError(this == 0,        "Tree", "next", "thistype", this, "Attempted To Go Out Of Bounds.")
            debug call ThrowError(not isCollection, "Tree", "next", "thistype", this, "Attempted To Read Invalid Node.")
            return _next
        endmethod
        
        private thistype _prev
        
        private thistype _first
        method operator children takes nothing returns thistype
            debug call ThrowError(this == 0,        "Tree", "children", "thistype", this, "Attempted To Read Null Node.")
            debug call ThrowError(not isCollection, "Tree", "children", "thistype", this, "Attempted To Read Invalid Node.")
            return _first
        endmethod
        
        private thistype _last
        
        static method operator sentinel takes nothing returns integer
            return 0
        endmethod
        
        private static method _allocateCollection takes nothing returns thistype
            local thistype this = thistype(0)._first
            
            if (0 == this) then
                debug call ThrowError(collectionCount == 8191, "Tree", "allocateCollection", "thistype", 0, "Overflow.")
                
                set this = collectionCount + 1
                set collectionCount = this
            else
                set thistype(0)._first = _first
            endif
            
            return this
        endmethod
        
        private method _enqueue takes nothing returns thistype
            local thistype node = _allocateCollection()
            
            set node._root = this
        
            if (_first == 0) then
                set _first = node
                set _last = node
                set node._prev = 0
            else
                set _last._next = node
                set node._prev = _last
                set _last = node
            endif
            
            set node._next = 0
            
            return node
        endmethod
        private method _remove takes nothing returns nothing
            local thistype node = this
            set this = node._root
            
            set node._root = 0
        
            if (0 == node._prev) then
                set _first = node._next
            else
                set node._prev._next = node._next
            endif
            if (0 == node._next) then
                set _last = node._prev
            else
                set node._next._prev = node._prev
            endif
            
            set node._next = thistype(0)._next
            set thistype(0)._next = node
        endmethod
        private method _clear takes nothing returns nothing
            if (_first == 0) then
                return
            endif
            
            set _last._next = thistype(0)._next
            set thistype(0)._next = _first
            
            set _first = 0
            set _last = 0
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = _allocateCollection()
                
            debug set isCollection = true
            
            return this
        endmethod
        
        method destroy takes nothing returns nothing
            local thistype node = _first
            local thistype next
            
            debug call ThrowError(this == 0,            "Tree", "destroy", "thistype", this, "Attempted To Destroy Null Tree.")
            debug call ThrowError(not isCollection,     "Tree", "destroy", "thistype", this, "Attempted To Destroy Invalid Tree.")
            
            loop
                exitwhen node == 0
                
                set next = node.next
                
                call node._remove()
                call node.destroy()
                
                set node = next
            endloop
            
            call _clear()
            
            if (_root != 0) then
                call ._remove()
            
                set _root = 0
            endif
            
            set _first = thistype(0)._first
            set thistype(0)._first = this
            
            debug set isCollection = false
        endmethod
        
        method clear takes nothing returns nothing
            local thistype node = _first
            local thistype next
        
            debug call ThrowError(this == 0,            "Tree", "clear", "thistype", this, "Attempted To Clear Null Tree.")
            debug call ThrowError(not isCollection,     "Tree", "clear", "thistype", this, "Attempted To Clear Invalid Tree.")
            
            loop
                exitwhen node == 0
                
                set next = node.next
                
                call node.destroy()
                
                set node = next
            endloop
            
            set _first = 0
            set _last = 0
        endmethod
        
        method insert takes nothing returns thistype
            local thistype node
            
            debug call ThrowError(this == 0,            "Tree", "insert", "thistype", this, "Attempted To Insert To Null Tree.")
            debug call ThrowError(not isCollection,     "Tree", "insert", "thistype", this, "Attempted To Insert To Invalid Tree.")
            
            set node = _enqueue()
            
            debug set node.isCollection = true
            
            return node
        endmethod
        
        static if DEBUG_MODE then
            static method calculateMemoryUsage takes nothing returns integer
                local thistype start = 1
                local thistype end = collectionCount
                local integer count = 0
                
                loop
                    exitwhen integer(start) > integer(end)
                    if (integer(start) + 500 > integer(end)) then
                        return count + checkRegion(start, end)
                    else
                        set count = count + checkRegion(start, start + 500)
                        set start = start + 501
                    endif
                endloop
                
                return count
            endmethod
              
            private static method checkRegion takes thistype start, thistype end returns integer
                local integer count = 0
            
                loop
                    exitwhen integer(start) > integer(end)
                    if (start.isCollection) then
                        set count = count + 1
                    endif
                    set start = start + 1
                endloop
                
                return count
            endmethod
            
            static method getAllocatedMemoryAsString takes nothing returns string
                local thistype start = 1
                local thistype end = collectionCount
                local string memory = null
                
                loop
                    exitwhen integer(start) > integer(end)
                    if (integer(start) + 500 > integer(end)) then
                        if (memory != null) then
                            set memory = memory + ", "
                        endif
                        set memory = memory + checkRegion2(start, end)
                        set start = end + 1
                    else
                        if (memory != null) then
                            set memory = memory + ", "
                        endif
                        set memory = memory + checkRegion2(start, start + 500)
                        set start = start + 501
                    endif
                endloop
                
                return memory
            endmethod
              
            private static method checkRegion2 takes thistype start, thistype end returns string
                local string memory = null
            
                loop
                    exitwhen integer(start) > integer(end)
                    if (start.isCollection) then
                        if (memory == null) then
                            set memory = I2S(start)
                        else
                            set memory = memory + ", " + I2S(start) + "C"
                        endif
                    endif
                    set start = start + 1
                endloop
                
                return memory
            endmethod
        endif
    endmodule
endlibrary

And some example code

JASS:
struct UniqueQueue extends array
    implement UniqueQueue
endstruct

struct TreeTester extends array
    /*
    *   readonly string string
    *   readonly integer size
    */
    implement Tree
    
    string identifier
    
    private method insertEx takes string identifier returns thistype
        local thistype node = insert()
        
        set node.identifier = identifier
        
        return node
    endmethod
    
    private method breadthfirst takes nothing returns nothing
        local UniqueQueue queue = UniqueQueue.create()
        local UniqueQueue children
        
        local thistype node = this.children
        local UniqueQueue child
        
        local string line

        //first put into queue
        loop
            exitwhen node == 0

            call queue.enqueue(node)

            set node = node.next
        endloop

        loop
            set child = queue.first
            exitwhen child == 0
            
            set line = ""
            set children = UniqueQueue.create()
            loop
                if (line != "") then
                    set line = line + ", "
                endif
                set line = line + thistype(child).identifier
            
                set node = thistype(child).children
                
                loop
                    exitwhen node == 0

                    call children.enqueue(node)

                    set node = node.next
                endloop
                
                set child = child.next
                exitwhen child == 0
            endloop
            call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,line)

            call queue.destroy()
            set queue = children
        endloop
        
        call queue.destroy()
    endmethod
    
    private static method init takes nothing returns nothing
        local thistype tree = create()
        
        local thistype c1 = tree.insertEx("1")
            local thistype c1_1 = c1.insertEx("1.1")
        local thistype c2 = tree.insertEx("2")
        local thistype c3 = tree.insertEx("3")
            local thistype c3_1 = c3.insertEx("3.1")
            local thistype c3_2 = c3.insertEx("3.2")
                local thistype c3_2_1 = c3_2.insertEx("3.2.1")
                    local thistype c3_2_1_1 = c3_2_1.insertEx("3.2.1.1")
        local thistype c4 = tree.insertEx("4")
        local thistype c5 = tree.insertEx("5")
        
        set tree.identifier = "root"
        
        call tree.breadthfirst()
        
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
        
        call c3.destroy()
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
        
        call c1_1.destroy()
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
        
        call c4.destroy()
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
        
        call c5.destroy()
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
        
        call tree.destroy()
        //call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,tree.string)
        call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,"Memory Usage: " + I2S(calculateMemoryUsage()))
    endmethod
    
    private static method init0 takes nothing returns nothing
        call DestroyTimer(GetExpiredTimer())
        call init.execute()
    endmethod

    private static method onInit takes nothing returns nothing
        call TimerStart(CreateTimer(),0,false,function thistype.init0)
    endmethod
    
    private method operator string takes nothing returns string
        local string base = identifier + "("
        local string s = base
        local thistype node = children
        
        loop
            exitwhen node == sentinel
            
            if (s != base) then
                set s = s + ", "
            endif
            
            set s = s + node.string
            
            set node = node.next
        endloop
        
        return s + ")"
    endmethod
    
    private method operator size takes nothing returns integer
        local integer sz = 0
        local thistype node = children
        
        loop
            exitwhen node == sentinel
            
            set sz = sz + node.size
            
            set node = node.next
        endloop
        
        return sz + 1
    endmethod
endstruct
 
Last edited:
Status
Not open for further replies.
Top