• 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.

TableSort

Status
Not open for further replies.
Work In Progress

Because, why not?

probably, going to extend the Table struct.

JASS:
library TableSort/*
*************************************************************************************
*
*   Table sorting algorithms
*
*   Sorting algorithms include:
*   - gnome sort
*   - insertion sort
*   - cycle sort
*   - shell sort
*   - comb sort
*   - bubble sort
*   - cocktail sort
*   - quick sort
*   - merge sort
*   - heap sort
*
*************************************************************************************
*
*   */ requires /*
*
*   */ Table /*
*
*************************************************************************************
*
*   API
*
*   TableSort(myTable).<real or int>.<name of sorting method>(startIndex, endIndex, ascending)
*   
*   <StructName>Sort.<name of sorting method>(startIndex, endIndex, ascending)
*************************************************************************************/

    private function Real2S takes real r returns string
        return R2S(r)
    endfunction
    private function Int2S takes integer r returns string
        return I2S(r)
    endfunction
    //! textmacro TABLE_SORT takes STRUCT, KEY, TYPE
    struct $STRUCT$Sort extends array
        method print takes string tname, integer start, integer end returns nothing
            local string s = tname + " = [ "
            local integer i = start
            local Table t = table
            loop
                set s = s + $STRUCT$2S(t$KEY$[i])
                set i = i + 1
                exitwhen i > end
                set s = s + ", "
            endloop
            set s = s + " ]"
            //call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 30, s)
            call Log.write(s)
        endmethod
        
        method operator table takes nothing returns Table
            return Table(this)
        endmethod
        
        method sorted takes integer start, integer end, boolean asc returns boolean
            local Table t = table
            loop
                exitwhen start > end
                if (asc and t$KEY$[start] < t$KEY$[start + 1]) != (not asc and t$KEY$[start] > t$KEY$[start + 1]) then
                    return false 
                endif
                set start = start + 1
            endloop
            return true
        endmethod
        
        private method swap takes integer j, integer k returns nothing
            local $TYPE$ temp = table$KEY$[j]
            set table$KEY$[j] = table$KEY$[k]
            set table$KEY$[k] = temp
        endmethod
        
        method gnome takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer i = start + 1
            local integer pos
            loop
                exitwhen i > end
                if sorted(start, end, asc) then
                    return
                endif
                set pos = i
                loop
                    exitwhen pos <= start or ((asc and t$KEY$[pos - 1] < t$KEY$[pos]) != (not asc and t$KEY$[pos - 1] > t$KEY$[pos]))
                    call swap(pos - 1, pos)
                    set pos = pos - 1
                endloop
                set i = i + 1
                debug call print("t", start, end)
            endloop
        endmethod
        
        method insertion takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer i = start + 1
            local integer pos
            local $TYPE$ value
            loop
                exitwhen i > end 
                if sorted(start, end, asc) then
                    return
                endif
                set value = t$KEY$[i]
                set pos = i - 1
                loop
                    exitwhen not (pos >= start and ((asc and t$KEY$[pos] > value) != (not asc and t$KEY$[pos] < value)))
                    set t$KEY$[pos + 1] = t$KEY$[pos]
                    set pos = pos - 1
                endloop
                set t$KEY$[pos + 1] = value
                set i = i + 1
                debug call print("t", start, end)
            endloop
        endmethod
        
        method cycle takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer cs = start
            local integer pos 
            local integer i
            local $TYPE$ val
            local $TYPE$ tmp
            loop
                exitwhen cs >= end 
                if sorted(start, end, asc) then
                    return
                endif
                set val = t$KEY$[cs]
                set pos = cs
                set i = cs
                loop
                    exitwhen i > end 
                    if (asc and t$KEY$[i] < val) != (not asc and t$KEY$[i] > val) then
                        set pos = pos + 1
                    endif
                    set i = i + 1
                endloop
                if pos != cs then
                    loop
                        exitwhen val != t$KEY$[pos]
                        set pos = pos + 1
                    endloop
                    set tmp = t$KEY$[pos]
                    set t$KEY$[pos] = val
                    set val = tmp
                    loop
                        exitwhen pos == cs
                        set pos = cs
                        set i = cs + 1
                        loop
                            exitwhen i > end 
                            if (asc and t$KEY$[i] < val) != (not asc and t$KEY$[i] > val) then
                                set pos = pos + 1
                            endif
                            set i = i + 1
                        endloop
                        loop
                            exitwhen val != t$KEY$[pos]
                            set pos = pos + 1
                        endloop
                        set tmp = t$KEY$[pos]
                        set t$KEY$[pos] = val
                        set val = tmp
                    endloop
                endif
                set cs = cs + 1
            endloop
        endmethod
        
        method shell takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer inc = (end - start)/2
            local $TYPE$ temp
            local integer i
            local integer j
            loop
                exitwhen inc <= 0
                if sorted(start, end, asc) then
                    return
                endif
                set i = start + inc
                loop
                    exitwhen i > (end - start)
                    set temp = t$KEY$[i]
                    set j = i
                    loop
                        exitwhen not (j >= start + inc and ((asc and t$KEY$[j - inc] > temp) != (not asc and t$KEY$[j - inc] < temp)))
                        set t$KEY$[j] = t$KEY$[j - inc]
                        set j = j - inc
                    endloop
                    set t$KEY$[j] = temp
                    set i = i + 1
                endloop
                
                set inc = R2I(0.5 + I2R(inc)/2.2)
                debug call print("t", start, end)
            endloop
        endmethod
        
        method comb takes integer start, integer end, boolean asc returns nothing
            local integer gap = end - start
            local integer swaps = 0
            local integer k
            
            local Table t = table
            loop
                exitwhen gap + swaps <= 1
                if sorted(start, end, asc) then
                    return
                endif
                set swaps = 0
                if gap > 1 then
                    set gap = R2I(I2R(gap)/1.2473)
                endif
                set k = start
                loop
                    exitwhen k > (end - gap)
                    if (asc and t$KEY$[k] > t$KEY$[k + gap]) != (not asc and t$KEY$[k] < t$KEY$[k + gap]) then
                        call swap(k, k + gap)
                        set swaps = swaps + 1
                    endif
                    set k = k + 1
                endloop
                debug call print("t", start, end)
            endloop
        endmethod
        
        method bubble takes integer start, integer end, boolean asc returns nothing
            local boolean swapped
            local integer i
            debug local integer e = end
            local Table t = table
            loop
                set swapped = false
                set i = start
                loop
                    if (asc and t$KEY$[i] > t$KEY$[i + 1]) != (not asc and t$KEY$[i] < t$KEY$[i + 1]) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == end - 1
                    set i = i + 1
                endloop
                set end = end - 1
                exitwhen not swapped
                debug call print("t", start, e)
            endloop
        endmethod
        
        method cocktail takes integer start, integer end, boolean asc returns nothing
            local boolean swapped
            local integer i
            local Table t = table
            loop
                set swapped = false
                set i = start
                loop
                    if (asc and t$KEY$[i] > t$KEY$[i + 1]) != (not asc and t$KEY$[i] < t$KEY$[i + 1]) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == end - 1
                    set i = i + 1
                endloop
                exitwhen not swapped
                set swapped = false
                set i = end - 1
                loop
                    if (asc and t$KEY$[i] > t$KEY$[i + 1]) != (not asc and t$KEY$[i] < t$KEY$[i + 1]) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == start
                    set i = i - 1
                endloop
                debug call print("t", start, end)
            endloop
        endmethod
        
        private method qpartition takes integer start, integer end, boolean asc returns integer
            local Table t = table
            local $TYPE$ x = t$KEY$[end]
            local integer i = start
            local integer j = i
            loop
                exitwhen j > end
                if (asc and t$KEY$[j] < x) != (not asc and t$KEY$[j] > x) then
                    call swap(i, j)
                    set i = i + 1
                endif
                set j = j + 1
            endloop
            call swap(i, end)
            return i 
        endmethod
        method quick takes integer start, integer end, boolean asc returns nothing
            local Table qstack = Table.create()
            local integer top = -1
            
            local integer p
            
            local integer s
            local integer e
            
            set top = top + 1
            set qstack[top] = start
            set top = top + 1
            set qstack[top] = end
            
            loop
                exitwhen top == -1
                set e = qstack[top]
                set top = top - 1
                set s = qstack[top]
                set top = top - 1
                if sorted(start, end, asc) then
                    call qstack.destroy()
                    return
                endif
                set p = qpartition(s, e, asc)
                if p - 1 > s then
                    set top = top + 1
                    set qstack[top] = s
                    set top = top + 1
                    set qstack[top] = p - 1
                endif
                if p + 1 < e then
                    set top = top + 1
                    set qstack[top] = p + 1
                    set top = top + 1
                    set qstack[top] = e
                endif
                
                debug call print("t", start, end)
            endloop
            
            call qstack.destroy()
        endmethod
        
        private method mergeValue takes integer l, integer le, integer r, integer re, boolean asc returns nothing
            local Table t = table
            
            local integer i = l
            local integer j = r
            local integer k = 0
            
            local Table left = Table.create()
            local Table right = Table.create()
            loop
                exitwhen i > le
                set left$KEY$[i] = t$KEY$[i]
                set i = i + 1
            endloop
            loop
                exitwhen j > re
                set right$KEY$[j] = t$KEY$[j]
                set j = j + 1
            endloop
            set i = l
            set j = r
            set k = l
            loop
                exitwhen i > le or j > re
                if (asc and left$KEY$[i] < right$KEY$[j]) != (not asc and left$KEY$[i] > right$KEY$[j]) then
                    set t$KEY$[k] = left$KEY$[i]
                    set i = i + 1
                else
                    set t$KEY$[k] = right$KEY$[j]
                    set j = j + 1
                endif
                set k = k + 1
            endloop
            loop
                exitwhen i > le
                set t$KEY$[k] = left$KEY$[i]
                set i = i + 1
                set k = k + 1
            endloop
            loop
                exitwhen j > re
                set t$KEY$[k] = right$KEY$[j]
                set j = j + 1
                set k = k + 1
            endloop
            call left.destroy()
            call right.destroy()
        endmethod
        
        method merge takes integer start, integer end, boolean asc returns nothing
            local Table stack = Table.create()
            local integer top = -1
            local integer m = 0
            local integer s
            local integer e
            set top = top + 1
            set stack[top] = start
            set top = top + 1
            set stack[top] = end
            
            loop
                exitwhen top < 0
                set e = stack[top]
                set top = top - 1
                set s = stack[top]
                set top = top - 1
                if sorted(start, end, asc) then
                    return
                endif
                if (e - s) > 0 then
                    set m = (s + e)/2
                    set top = top + 1
                    set stack[top] = s
                    set top = top + 1
                    set stack[top] = m
                    set top = top + 1
                    set stack[top] = m + 1
                    set top = top + 1
                    set stack[top] = e
            
                    call mergeValue(s, m, m + 1, e, asc)
                endif
                debug call print("t", start, end)
            endloop
            call stack.destroy()
        endmethod
        
        private method siftDown takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer root = start
            local integer child
            loop
                set child = root*2 + 1
                exitwhen child > end
                if child + 1 <= end and ((asc and t$KEY$[child] < t$KEY$[child + 1]) != (not asc and t$KEY$[child] > t$KEY$[child + 1])) then
                    set child = child + 1
                endif 
                if ((asc and t$KEY$[root] < t$KEY$[child]) != (not asc and t$KEY$[root] > t$KEY$[child])) then
                    call swap(root, child)
                    set root = child
                else
                    return
                endif
            endloop
        endmethod
        
        method heap takes integer start, integer end, boolean asc returns nothing
            local integer s = (end + start)/2
            local integer e = end
            loop
                exitwhen s < start 
                if sorted(start, end, asc) then
                    return
                endif
                call siftDown(s, end, asc)
                set s = s - 1
                debug call print("t", start, end) 
            endloop
            loop
                exitwhen e <= start
                if sorted(start, end, asc) then
                    return
                endif
                call swap(start, e)
                call siftDown(start, e - 1, asc)
                set e = e - 1
                debug call print("t", start, end)
            endloop
        endmethod
    endstruct
    //! endtextmacro
    
    //! runtextmacro TABLE_SORT("Int", ".integer", "integer")
    //! runtextmacro TABLE_SORT("Real", ".real", "real")
    
    struct TableSort extends array
        method operator real takes nothing returns RealSort
            return this
        endmethod
        
        method operator int takes nothing returns IntSort
            return this
        endmethod
    endstruct
    
    //! textmacro STRUCT_SORT takes STRUCT
    struct $STRUCT$Sort extends array
        method operator table takes nothing returns Table
            return Table(this)
        endmethod
        
        private method swap takes integer j, integer k returns nothing
            local integer temp = table.integer[j]
            set table.integer[j] = table.integer[k]
            set table.integer[k] = temp
        endmethod
        
        method gnome takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer i = start + 1
            local integer pos
            loop
                exitwhen i > end
                set pos = i
                loop
                    exitwhen pos <= start or ((asc and $STRUCT$(t.integer[pos - 1]) < $STRUCT$(t.integer[pos])) != (not asc and $STRUCT$(t.integer[pos - 1]) > $STRUCT$(t.integer[pos])))
                    call swap(pos - 1, pos)
                    set pos = pos - 1
                endloop
                set i = i + 1
            endloop
        endmethod
        
        method insertion takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer i = start + 1
            local integer pos
            local $STRUCT$ value
            loop
                exitwhen i > end 
                set value = $STRUCT$(t.integer[i])
                set pos = i - 1
                loop
                    exitwhen not (pos >= start and ((asc and $STRUCT$(t.integer[pos]) > value) != (not asc and $STRUCT$(t.integer[pos]) < value)))
                    set t.integer[pos + 1] = t.integer[pos]
                    set pos = pos - 1
                endloop
                set t.integer[pos + 1] = value
                set i = i + 1
            endloop
        endmethod
        
        method cycle takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer cs = start
            local integer pos 
            local integer i
            local $STRUCT$ val
            local $STRUCT$ tmp
            loop
                exitwhen cs >= end 
                set val = $STRUCT$(t.integer[cs])
                set pos = cs
                set i = cs
                loop
                    exitwhen i > end 
                    if (asc and $STRUCT$(t.integer[i]) < val) != (not asc and $STRUCT$(t.integer[i]) > val) then
                        set pos = pos + 1
                    endif
                    set i = i + 1
                endloop
                if pos != cs then
                    loop
                        exitwhen val != $STRUCT$(t.integer[pos])
                        set pos = pos + 1
                    endloop
                    set tmp = $STRUCT$(t.integer[pos])
                    set t.integer[pos] = val
                    set val = tmp
                    loop
                        exitwhen pos == cs
                        set pos = cs
                        set i = cs + 1
                        loop
                            exitwhen i > end 
                            if (asc and $STRUCT$(t.integer[i]) < val) != (not asc and $STRUCT$(t.integer[i]) > val) then
                                set pos = pos + 1
                            endif
                            set i = i + 1
                        endloop
                        loop
                            exitwhen val != $STRUCT$(t.integer[pos])
                            set pos = pos + 1
                        endloop
                        set tmp = $STRUCT$(t.integer[pos])
                        set t.integer[pos] = val
                        set val = tmp
                    endloop
                endif
                set cs = cs + 1
            endloop
        endmethod
        
        method shell takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer inc = (end - start)/2
            local $STRUCT$ temp
            local integer i
            local integer j
            loop
                exitwhen inc <= 0
                set i = start + inc
                loop
                    exitwhen i > (end - start)
                    set temp = $STRUCT$(t.integer[i])
                    set j = i
                    loop
                        exitwhen not (j >= start + inc and ((asc and $STRUCT$(t.integer[j - inc]) > temp) != (not asc and $STRUCT$(t.integer[j - inc]) < temp)))
                        set t.integer[j] = t.integer[j - inc]
                        set j = j - inc
                    endloop
                    set t.integer[j] = temp
                    set i = i + 1
                endloop
                
                set inc = R2I(0.5 + I2R(inc)/2.2)
            endloop
        endmethod
        
        method comb takes integer start, integer end, boolean asc returns nothing
            local integer gap = end - start
            local integer swaps = 0
            local integer k
            
            local Table t = table
            loop
                exitwhen gap + swaps <= 1
                set swaps = 0
                if gap > 1 then
                    set gap = R2I(I2R(gap)/1.2473)
                endif
                set k = start
                loop
                    exitwhen k > (end - gap)
                    if (asc and $STRUCT$(t.integer[k]) > $STRUCT$(t.integer[k + gap])) != (not asc and $STRUCT$(t.integer[k]) < $STRUCT$(t.integer[k + gap])) then
                        call swap(k, k + gap)
                        set swaps = swaps + 1
                    endif
                    set k = k + 1
                endloop
            endloop
        endmethod
        
        method bubble takes integer start, integer end, boolean asc returns nothing
            local boolean swapped
            local integer i
            debug local integer e = end
            local Table t = table
            loop
                set swapped = false
                set i = start
                loop
                    if (asc and $STRUCT$(t.integer[i]) > $STRUCT$(t.integer[i + 1])) != (not asc and $STRUCT$(t.integer[i]) < $STRUCT$(t.integer[i + 1])) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == end - 1
                    set i = i + 1
                endloop
                set end = end - 1
                exitwhen not swapped
            endloop
        endmethod
        
        method cocktail takes integer start, integer end, boolean asc returns nothing
            local boolean swapped
            local integer i
            local Table t = table
            loop
                set swapped = false
                set i = start
                loop
                    if (asc and $STRUCT$(t.integer[i]) > $STRUCT$(t.integer[i + 1])) != (not asc and $STRUCT$(t.integer[i]) < $STRUCT$(t.integer[i + 1])) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == end - 1
                    set i = i + 1
                endloop
                exitwhen not swapped
                set swapped = false
                set i = end - 1
                loop
                    if (asc and $STRUCT$(t.integer[i]) > $STRUCT$(t.integer[i + 1])) != (not asc and $STRUCT$(t.integer[i]) < $STRUCT$(t.integer[i + 1])) then
                        call swap(i, i + 1)
                        set swapped = true
                    endif
                    exitwhen i == start
                    set i = i - 1
                endloop
            endloop
        endmethod
        
        private method qpartition takes integer start, integer end, boolean asc returns integer
            local Table t = table
            local $STRUCT$ x = $STRUCT$(t.integer[end])
            local integer i = start
            local integer j = i
            loop
                exitwhen j > end
                if (asc and $STRUCT$(t.integer[j]) < x) != (not asc and $STRUCT$(t.integer[j]) > x) then
                    call swap(i, j)
                    set i = i + 1
                endif
                set j = j + 1
            endloop
            call swap(i, end)
            return i 
        endmethod
        method quick takes integer start, integer end, boolean asc returns nothing
            local Table qstack = Table.create()
            local integer top = -1
            
            local integer p
            
            local integer s
            local integer e
            
            set top = top + 1
            set qstack[top] = start
            set top = top + 1
            set qstack[top] = end
            
            loop
                exitwhen top == -1
                set e = qstack[top]
                set top = top - 1
                set s = qstack[top]
                set top = top - 1
                set p = qpartition(s, e, asc)
                if p - 1 > s then
                    set top = top + 1
                    set qstack[top] = s
                    set top = top + 1
                    set qstack[top] = p - 1
                endif
                if p + 1 < e then
                    set top = top + 1
                    set qstack[top] = p + 1
                    set top = top + 1
                    set qstack[top] = e
                endif
            endloop
            
            call qstack.destroy()
        endmethod
        
        private method mergeValue takes integer l, integer le, integer r, integer re, boolean asc returns nothing
            local Table t = table
            
            local integer i = l
            local integer j = r
            local integer k = 0
            
            local Table left = Table.create()
            local Table right = Table.create()
            loop
                exitwhen i > le
                set left.integer[i] = t.integer[i]
                set i = i + 1
            endloop
            loop
                exitwhen j > re
                set right.integer[j] = t.integer[j]
                set j = j + 1
            endloop
            set i = l
            set j = r
            set k = l
            loop
                exitwhen i > le or j > re
                if (asc and $STRUCT$(left.integer[i]) < $STRUCT$(right.integer[j])) != (not asc and $STRUCT$(left.integer[i]) > $STRUCT$(right.integer[j])) then
                    set t.integer[k] = left.integer[i]
                    set i = i + 1
                else
                    set t.integer[k] = right.integer[j]
                    set j = j + 1
                endif
                set k = k + 1
            endloop
            loop
                exitwhen i > le
                set t.integer[k] = left.integer[i]
                set i = i + 1
                set k = k + 1
            endloop
            loop
                exitwhen j > re
                set t.integer[k] = right.integer[j]
                set j = j + 1
                set k = k + 1
            endloop
            call left.destroy()
            call right.destroy()
        endmethod
        
        method merge takes integer start, integer end, boolean asc returns nothing
            local Table stack = Table.create()
            local integer top = -1
            local integer m = 0
            local integer s
            local integer e
            set top = top + 1
            set stack[top] = start
            set top = top + 1
            set stack[top] = end
            
            loop
                exitwhen top < 0
                set e = stack[top]
                set top = top - 1
                set s = stack[top]
                set top = top - 1
                if (e - s) > 0 then
                    set m = (s + e)/2
                    set top = top + 1
                    set stack[top] = s
                    set top = top + 1
                    set stack[top] = m
                    set top = top + 1
                    set stack[top] = m + 1
                    set top = top + 1
                    set stack[top] = e
            
                    call mergeValue(s, m, m + 1, e, asc)
                endif
            endloop
            call stack.destroy()
        endmethod
        
        private method siftDown takes integer start, integer end, boolean asc returns nothing
            local Table t = table
            local integer root = start
            local integer child
            loop
                set child = root*2 + 1
                exitwhen child > end
                if child + 1 <= end and ((asc and $STRUCT$(t.integer[child]) < $STRUCT$(t.integer[child + 1])) != (not asc and $STRUCT$(t.integer[child]) > $STRUCT$(t.integer[child + 1]))) then
                    set child = child + 1
                endif 
                if ((asc and $STRUCT$(t.integer[root]) < $STRUCT$(t.integer[child])) != (not asc and $STRUCT$(t.integer[root]) > $STRUCT$(t.integer[child]))) then
                    call swap(root, child)
                    set root = child
                else
                    return
                endif
            endloop
        endmethod
        
        method heap takes integer start, integer end, boolean asc returns nothing
            local integer s = (end + start)/2
            local integer e = end
            loop
                exitwhen s < start 
                call siftDown(s, end, asc)
                set s = s - 1
            endloop
            loop
                exitwhen e <= start
                call swap(start, e)
                call siftDown(start, e - 1, asc)
                set e = e - 1
            endloop
        endmethod
    endstruct
    //! endtextmacro
endlibrary

all codes will be based from :
http://rosettacode.org/wiki/Category:Sorting_Algorithms

Note: all sorting algorithms will be non-recursive.
 
Last edited:
Some thoughts.

When you already work with table, you obviously want to offer sorting of complex data types, and not only reals/integers.
But then it would only make sense if the user has access to customize the comparison.

So if the comparison like this will stay static...
t$KEY$[i] > t$KEY$[i + 1]
... it could directly use only reals.

example

just for the lulz: http://img.pr0gramm.com/2016/03/04/9d5f938b24ad6d8b.webm
 
Status
Not open for further replies.
Top