Binary Insert

lua-users home
wiki

Insert a Value Directly into a Sorted Table

This function inserts a value into a sorted table via a binary search algorithm. It is faster than doing a regular table.insert(table, value) followed by a table.sort(table [, comp]).

Files:wiki_insecure/users/chill/table.binsearch-0.3.lua

--[[
   table.bininsert( table, value [, comp] )
   
   Inserts a given value through BinaryInsert into the table sorted by [, comp].
   
   If 'comp' is given, then it must be a function that receives
   two table elements, and returns true when the first is less
   than the second, e.g. comp = function(a, b) return a > b end,
   will give a sorted table, with the biggest value on position 1.
   [, comp] behaves as in table.sort(table, value [, comp])
   returns the index where 'value' was inserted
]]--
do
   -- Avoid heap allocs for performance
   local fcomp_default = function( a,b ) return a < b end
   function table.bininsert(t, value, fcomp)
      -- Initialise compare function
      local fcomp = fcomp or fcomp_default
      --  Initialise numbers
      local iStart,iEnd,iMid,iState = 1,#t,1,0
      -- Get insert position
      while iStart <= iEnd do
         -- calculate middle
         iMid = math.floor( (iStart+iEnd)/2 )
         -- compare
         if fcomp( value,t[iMid] ) then
            iEnd,iState = iMid - 1,0
         else
            iStart,iState = iMid + 1,1
         end
      end
      table.insert( t,(iMid+iState),value )
      return (iMid+iState)
   end
end
-- CHILLCODE™

Test suite:

-- test: typical usage, with duplicates
t = {}
table.bininsert(t,  5)
assert(table.concat(t) == "5")
table.bininsert(t,  4)
assert(table.concat(t) == "45")
table.bininsert(t,  6)
assert(table.concat(t) == "456")
table.bininsert(t,  5)
assert(table.concat(t) == "4556")
table.bininsert(t,  6)
assert(table.concat(t) == "45566")
table.bininsert(t,  4)
assert(table.concat(t) == "445566")
table.bininsert(t,  0)
assert(table.concat(t) == "0445566")

-- test: fcomp
fcomp = function(a, b) return (a%3) < (b%3) end
t = {}
table.bininsert(t, 9, fcomp)
assert(table.concat(t) == "9")
table.bininsert(t, 3, fcomp)
assert(table.concat(t) == "93")
table.bininsert(t, 6, fcomp)
assert(table.concat(t) == "936")
table.bininsert(t, 2, fcomp)
assert(table.concat(t) == "9362")
table.bininsert(t, 7, fcomp)
assert(table.concat(t) == "93672")
table.bininsert(t, 1, fcomp)
assert(table.concat(t) == "936712")
table.bininsert(t, 5, fcomp)
assert(table.concat(t) == "9367125")
table.bininsert(t, 8, fcomp)
assert(table.concat(t) == "93671258")
table.bininsert(t, 4, fcomp)
assert(table.concat(t) == "936714258")
print "DONE"

See Also


RecentChanges · preferences
edit · history
Last edited September 6, 2009 3:01 am GMT (diff)