I don’t really use this and its unlikely that I ever will so I am releasing it here. This thread contains some data structures that are commonly used outside of Roblox.
The code is not perfectly written because I wrote a little more than a year ago. Hopefully somebody finds it useful.
Binary search tree
--[[
BST
not auto balance
--]]
-- Constants
-- efficieny variables
local setmetatable=setmetatable
-- local variables
--[[
Tree: Root
Node: Parent, Left, Right, Data
--]]
local function newnode(data)
return{
false,-- Parent
false,-- Left
false,-- Right
data,}
end
local function find(tree,data)
local c=tree.root
while c do
local d=c[4]
if data<d then
c=c[2]
elseif data>d then
c=c[3]
else
return c
end
end
end
local function lowerbound(tree,v)
-- returns node if exists, else nil
local y
local x=tree.root
while x do
if x[4]>=v then
y=x
x=x[2]
else
x=x[3]
end
end
return y
end
local function upperbound(tree,v)
-- returns node if exists, else nil
local y
local x=tree.root
while x do
if x[4]>v then
x=x[2]
else
y=x
x=x[3]
end
end
return y
end
local function insert(tree,data)
local n=newnode(data)
local c=tree.root
if c then
local l=c[2]
local r=c[3]
while true do
if data<c[4]then
if l then
c=l
r=l[3]
l=l[2]
else
c[2]=n
n[1]=c
break
end
else
if r then
c=r
l=r[2]
r=r[3]
else
c[3]=n
n[1]=c
break
end
end
end
else
tree.root=n
end
return n
end
local function deletenode(tree,n)
-- find successor
local right=n[3]
local left=n[2]
if right and left then
local succ
local temp=right[2]
while temp do
succ=temp
temp=succ[2]
end
local par=n[1]
if succ then
if par then
if par[2]==n then
par[2]=succ
else
par[3]=succ
end
end
temp=succ[3]
succ[1][2]=temp
succ[3]=right
if temp then
temp[1]=succ[1]
end
right=succ
else
if par then
if par[2]==n then
par[2]=right
else
par[3]=right
end
end
end
right[1]=par
right[2]=left
elseif right then
local par=n[1]
if par then
if par[2]==n then
par[2]=right
else
par[3]=right
end
end
right[1]=par
elseif left then
right=left
local par=n[1]
if par then
if par[2]==n then
par[2]=right
else
par[3]=right
end
end
right[1]=par
end
if n==tree.root then
tree.root=right
end
end
local function deletedata(tree,data)
deletenode(tree,find(tree,data))
end
local function empty(tree)
return tree.root==nil
end
local function printnode(node,prefix,istail)
if not node then
return''
end
local s='\n'..prefix..((istail and'\226\148\148\226\148\128\226\148\128 ')or'\226\148\156\226\148\128\226\148\128 ')..node[4]
prefix=prefix..((istail and' ')or'\226\148\130 ')
local l=node[2]
local r=node[3]
if l and r then
-- right then left first so if you do 90º clockwise Rotation it looks like a BST
return s..printnode(r,prefix)..printnode(l,prefix,true)
elseif l then
return s..printnode(l,prefix,true)
elseif r then
return s..printnode(r,prefix,true)
else
return s
end
end
local function dc(a,s,e)
-- divide and conquer to construct a perfect BST
if e<=s then
e=newnode(a[s])
e[5]=true
return e
else
local m=(s+e)/2
m=m-m%1
local x=newnode(a[m])
if s<m then
-- edge case which causes some nodes to be inserted twice
x[2]=dc(a,s,m-1)
x[2][1]=x
end
x[3]=dc(a,m+1,e)
x[3][1]=x
return x
end
end
--[[
local function isBST(node, minKey, maxKey)
if node == b.Nil then
return true
end
if node[4] < minKey or node[4] > maxKey then
return false
end
return isBST(node[2],minKey,node[4]-1) and isBST(node[3],node[4]+1,maxKey)
end
print(isBST(b.Root,-math.huge,math.huge))
--]]
local bst={
find=find,
insert=insert,
deletenode=deletenode,
deletedata=deletedata,
empty=empty,
__tostring=function(tree)
return printnode(tree.root,'',true)
end,
}
function bst.new(a)
local root
local Size
if a then
-- assumes SORTED array, if not sorted then call table.sort BEFORE passing it
Size=#a
root=(Size>0 and dc(a,1,Size))or nil
else
Size=0
end
local self={
root=root,
Size=Size,
empty=empty,
insert=insert,
deletenode=deletenode,
deletedata=deletedata,
find=find,
lowerbound=lowerbound,
upperbound=upperbound,
}
setmetatable(self,bst)
return self
end
return bst