-
Notifications
You must be signed in to change notification settings - Fork 0
/
tree.nim
320 lines (281 loc) · 8.59 KB
/
tree.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
import random, typetraits
type
DatomField* = enum
Entity,
Value,
Attribute
ValueType* = enum
Int,
String,
Float
Datom* = object
entity : int
attribute : int
case kind : ValueType
of Int:
intValue : int
of String:
stringValue : string
of Float:
floatValue : float
Treap* = ref TreapObj
TreapObj* = object
root : ref Node
order : seq[DatomField]
Node* = object
datom : Datom
priority : int
left : ref Node
right : ref Node
TreapIter* = object
node : ref Node
depth : int
atEnd : bool
var treap : Treap
var typeOrder : seq[ValueType] = @[Int, Float, String]
proc getTypeId(t : ValueType) : int =
var id : int = 0
for x in typeOrder:
if t == x:
return id
inc(id)
proc `<`(a : Datom, b : Datom): bool =
for field in treap.order:
if field == Value:
if a.kind == b.kind:
if a.kind == Int:
if a.intValue != b.intValue:
return a.intValue < b.intValue
elif a.kind == Float:
if a.floatValue != b.floatValue:
return a.floatValue < b.floatValue
elif a.kind == String:
if a.stringValue != b.stringValue:
return a.stringValue < b.stringValue
else:
var idA = getTypeId(a.kind)
var idB = getTypeId(b.kind)
return idA < idB
elif field == Entity:
if a.entity != b.entity:
return a.entity < b.entity
elif field == Attribute:
if a.attribute != b.attribute:
return a.attribute < b.attribute
return false
proc `==`(a : Datom, b : Datom): bool =
if a.kind != b.kind:
return false
if a.kind == Int and a.intValue != b.intValue:
return false
if a.kind == String and a.stringValue != b.stringValue:
return false
if a.kind == Float and a.floatValue != b.floatValue:
return false
return a.entity == b.entity and a.attribute == b.attribute
proc split(node : ref Node, key : Datom, leftTree : var ref Node, rightTree : var ref Node) =
if node == nil:
leftTree = nil
rightTree = nil
elif key < node.datom:
split(node.left, key, leftTree, node.left)
rightTree = node
else:
split(node.right, key, node.right, rightTree)
leftTree = node
proc setDatomFields(entity : int, attribute : int, datom : var Datom) =
datom.entity = entity
datom.attribute = attribute
proc createEmptyDatom() : Datom =
var datom : Datom
datom.kind = String
setDatomFields(-1, -1, datom)
datom.stringValue = "end iterator"
return datom
proc createIntDatom*(entity : int, attribute : int, value : int) : Datom =
var datom : Datom
datom.kind = Int
setDatomFields(entity, attribute, datom)
datom.intValue = value
return datom
proc createStringDatom*(entity : int, attribute : int, value : string) : Datom =
var datom : Datom
datom.kind = String
setDatomFields(entity, attribute, datom)
datom.stringValue = value
return datom
proc createFloatDatom*(entity : int, attribute : int, value : float) : Datom =
var datom : Datom
datom.kind = Float
setDatomFields(entity, attribute, datom)
datom.floatValue = value
return datom
proc createNode(datom : Datom) : ref Node =
var node : ref Node = new(Node)
node.datom = datom
node.priority = random(high(int))
node.left = nil
node.right = nil
return node
proc add(node : var ref Node, addNode : ref Node) =
if node == nil:
node = addNode
elif addNode[].priority > node[].priority:
split(node, addNode.datom, addNode.left, addNode.right)
node = addNode
else:
if addNode.datom < node.datom:
add(node.left, addNode)
else:
add(node.right, addNode)
proc add*(t : var Treap, datom : Datom) =
add(t.root, createNode(datom))
proc merge(node : var ref Node, leftTree : ref Node, rightTree : ref Node) =
if leftTree == nil:
node = rightTree
elif rightTree == nil:
node = leftTree
elif leftTree.priority > rightTree.priority:
merge(leftTree.right, leftTree.right, rightTree)
node = leftTree
else:
merge(rightTree.left, leftTree, rightTree.left)
node = rightTree
proc erase(node : var ref Node, key : Datom) =
if node.datom == key:
merge(node, node.left, node.right)
else:
if key < node.datom:
erase(node.left, key)
else:
erase(node.right, key)
proc erase*(t : Treap, key : Datom) =
erase(t.root, key)
proc seek(node : ref Node, key : Datom): ref Node =
if node == nil:
return nil
elif node.datom == key:
return node
elif node.datom < key:
return seek(node.right, key)
else:
var leftNode = seek(node.left, key)
if leftNode == nil:
return node
else:
return leftNode
proc seek*(t : Treap, key : Datom): TreapIter =
var node : ref Node = seek(t.root, key)
var it : TreapIter
if node == nil:
it.atEnd = true
else:
it.atEnd = false
it.node = node
return it
proc upperbound(node : ref Node, key : Datom): ref Node =
if node == nil:
return nil
elif node.datom == key or node.datom < key:
return upperbound(node.right, key)
else:
var leftNode = upperbound(node.left, key)
if leftNode == nil:
return node
else:
return leftNode
proc print(node : var ref Node) =
if node != nil:
if node.left != nil:
print(node.left)
echo node.datom
if node.right != nil:
print(node.right)
proc print*(t : var Treap) =
print(t.root)
proc atEnd*(it : var TreapIter): bool =
return it.atEnd
proc next*(it : var TreapIter) =
var nextNode = upperbound(treap.root, it.node.datom)
if (nextNode == nil):
it.atEnd = true
else:
var currentDepth : int = 0
var isGood : bool = true
for t in treap.order:
if currentDepth > it.depth:
break
if t == Value:
if it.node.datom.kind == String:
if nextNode.datom.stringValue != it.node.datom.stringValue:
isGood = false
break
elif it.node.datom.kind == Float:
if nextNode.datom.floatValue != it.node.datom.floatValue:
isGood = false
break
elif it.node.datom.kind == Int:
if nextNode.datom.intValue != it.node.datom.intValue:
isGood = false
break
elif t == Attribute:
if nextNode.datom.attribute != it.node.datom.attribute:
isGood = false
break
elif t == Entity:
if nextNode.datom.entity != it.node.datom.entity:
isGood = false
break
inc(currentDepth)
if not isGood:
it.atEnd = true
else:
it.atEnd = false
it.node = nextNode
proc begin*(root : ref Node): TreapIter =
var it : TreapIter
var node : ref Node = root
if node == nil:
it.node = nil
it.atEnd = true
return it
while node.left != nil:
node = node.left
it.node = node
it.atEnd = false
return it
proc open*(it : var TreapIter) =
inc(it.depth)
proc up*(it : var TreapIter) =
dec(it.depth)
it.atEnd = false
proc key*(it : TreapIter): Datom =
if it.atEnd:
return createEmptyDatom()
return it.node.datom
proc getTreap(node : ref Node, result : var seq[Datom]) =
if node != nil:
if node.left != nil:
getTreap(node.left, result)
result.add(node.datom)
if node.right != nil:
getTreap(node.right, result)
iterator preorder*(root : ref Node): Datom =
var nodes : seq[Datom]
nodes = @[]
getTreap(root, nodes)
for i in nodes:
yield(i)
proc createTreap*(order : seq[DatomField]): Treap =
var root : ref Node
root = nil
new(treap)
treap.root = root
treap.order = order
return treap
proc createTreapIter*(t : Treap): TreapIter =
var it : TreapIter
it.depth = -2
it.atEnd = false
it.node = begin(t.root).node
return it