added non-recursive iteration
This commit is contained in:
parent
5599a59e87
commit
5b436bad5a
1 changed files with 90 additions and 11 deletions
|
|
@ -169,6 +169,83 @@ proc dos(x: Node; kind: CmpKind; key: Key; withKey: proc(k: Key; v: Val)) =
|
||||||
for i in followA..followB:
|
for i in followA..followB:
|
||||||
dos(x.links[i], kind, key, withKey)
|
dos(x.links[i], kind, key, withKey)
|
||||||
|
|
||||||
|
proc don(x: Node; kind: CmpKind; key: Key; withKey: proc(k: Key; v: Val)) =
|
||||||
|
var stack = @[x]
|
||||||
|
while stack.len > 0:
|
||||||
|
let x = stack.pop()
|
||||||
|
if not x.isInternal:
|
||||||
|
for j in 0 ..< x.m:
|
||||||
|
if cmp(x.keys[j], key) =~ kind:
|
||||||
|
withKey(x.keys[j], x.vals[j])
|
||||||
|
else:
|
||||||
|
# we compute the range of links to follow first, before
|
||||||
|
# recursing:
|
||||||
|
var followA = 0
|
||||||
|
var followB = -1
|
||||||
|
case kind
|
||||||
|
of CmpKind.eq:
|
||||||
|
# want: key == 10
|
||||||
|
# keys: 0 3 4 5 10 20
|
||||||
|
# keys: 20 30 40
|
||||||
|
for j in 1..x.m:
|
||||||
|
if j == x.m or cmp(key, x.keys[j]) < 0:
|
||||||
|
followA = j-1
|
||||||
|
followB = j-1
|
||||||
|
break
|
||||||
|
of CmpKind.le, CmpKind.lt:
|
||||||
|
# want: key <= 10 or key < 10
|
||||||
|
# keys: 0 3 4 5 10 20
|
||||||
|
# keys: 20 30 40
|
||||||
|
|
||||||
|
# Case A: all keys are bigger:
|
||||||
|
if cmp(key, x.keys[1]) < 0:
|
||||||
|
# --> use the very first branch
|
||||||
|
followA = 0
|
||||||
|
followB = 0
|
||||||
|
else:
|
||||||
|
# Case B: all keys are smaller --> use all branches is covered too
|
||||||
|
# by this loop.
|
||||||
|
for j in 1..<x.m:
|
||||||
|
let cmpRes = cmp(key, x.keys[j])
|
||||||
|
if cmpRes >= 0:
|
||||||
|
if followB < 0: followA = j-1
|
||||||
|
# if the keys are identical and we require 'lt', we know
|
||||||
|
# only the left branch is required:
|
||||||
|
followB = j - ord(kind == CmpKind.lt and cmpRes == 0)
|
||||||
|
else:
|
||||||
|
# it's already greater, all others are greater too:
|
||||||
|
break
|
||||||
|
of CmpKind.ge, CmpKind.gt:
|
||||||
|
# want: key >= 10 or key > 10
|
||||||
|
# keys: 0 3 4 5 10 20
|
||||||
|
# keys: 20 30 40
|
||||||
|
|
||||||
|
# Case A: all keys are smaller:
|
||||||
|
if cmp(key, x.keys[x.m-1]) >= 0:
|
||||||
|
# --> use the very last branch
|
||||||
|
followA = x.m-1
|
||||||
|
followB = x.m-1
|
||||||
|
else:
|
||||||
|
# also covers case B: all keys are bigger --> use all branches
|
||||||
|
# we find the key that is bigger or equal to ours and from
|
||||||
|
# then on, follow every branch:
|
||||||
|
for j in 1..<x.m:
|
||||||
|
let cmpRes = cmp(key, x.keys[j])
|
||||||
|
if cmpRes <= 0:
|
||||||
|
# if the keys are identical and we need 'ge', we don't have
|
||||||
|
# to consider the 'j-1' branch:
|
||||||
|
followA = j - ord(kind != CmpKind.ge or cmpRes != 0)
|
||||||
|
# we know everything else is even bigger:
|
||||||
|
followB = x.m-1
|
||||||
|
break
|
||||||
|
of CmpKind.neq:
|
||||||
|
# neq: just follow all for now:
|
||||||
|
followA = 0
|
||||||
|
followB = x.m-1
|
||||||
|
# now recurse into the branches that hold candidates we're interested in:
|
||||||
|
for i in countdown(followB, followA):
|
||||||
|
stack.add(x.links[i])
|
||||||
|
|
||||||
proc init(x: Node): Cursor =
|
proc init(x: Node): Cursor =
|
||||||
result.up = @[]
|
result.up = @[]
|
||||||
result.i = 0
|
result.i = 0
|
||||||
|
|
@ -218,17 +295,6 @@ proc split(h: Node): Node =
|
||||||
h.m = Mhalf
|
h.m = Mhalf
|
||||||
copyHalf(h, result, Mhalf)
|
copyHalf(h, result, Mhalf)
|
||||||
|
|
||||||
when false:
|
|
||||||
# unnecessary because when we call 'split' we know it's not a
|
|
||||||
# shared node!
|
|
||||||
proc splitPs(h: Node): (Node, Node) =
|
|
||||||
## persistent variant of 'split'.
|
|
||||||
var a = Node(m: Mhalf, isInternal: h.isInternal)
|
|
||||||
var b = Node(m: Mhalf, isInternal: h.isInternal)
|
|
||||||
copyHalf(h, a, Mhalf)
|
|
||||||
copyHalf(h, b, 0)
|
|
||||||
result = (a, b)
|
|
||||||
|
|
||||||
proc insert(h: Node, key: Key, val: Val, ht: int): Node =
|
proc insert(h: Node, key: Key, val: Val, ht: int): Node =
|
||||||
#var t = Entry(key: key, val: val, next: nil)
|
#var t = Entry(key: key, val: val, next: nil)
|
||||||
var newKey = key
|
var newKey = key
|
||||||
|
|
@ -412,4 +478,17 @@ when isMainModule:
|
||||||
echo " > 5"
|
echo " > 5"
|
||||||
dos(b1.root, CmpKind.gt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
dos(b1.root, CmpKind.gt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
|
||||||
|
echo "======================================================================"
|
||||||
|
echo " >= 5"
|
||||||
|
don(b1.root, CmpKind.ge, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
echo " <= 5"
|
||||||
|
don(b1.root, CmpKind.le, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
|
||||||
|
echo " == 5"
|
||||||
|
don(b1.root, CmpKind.eq, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
echo " < 5"
|
||||||
|
don(b1.root, CmpKind.lt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
echo " > 5"
|
||||||
|
don(b1.root, CmpKind.gt, "5", proc(k: Key; v: Val) = echo("k ", k, " = ", v))
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue