Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/misc/binary_tree.pyx
8814 views
1
"""
2
Implements a binary tree in Cython.
3
4
AUTHORS:
5
6
- Tom Boothby (2007-02-15). Initial version free for any use (public domain).
7
"""
8
9
include 'sage/ext/stdsage.pxi'
10
include 'sage/ext/python.pxi'
11
12
cdef binary_tree_node *BinaryTreeNode(int key, object value):
13
cdef binary_tree_node *t
14
t = <binary_tree_node *>sage_malloc(sizeof(binary_tree_node))
15
t.key = key
16
t.left = NULL
17
t.right = NULL
18
Py_INCREF(value)
19
t.value = <void *>value
20
return t
21
22
cdef void free_binary_tree_node(binary_tree_node *self):
23
if self.value != NULL:
24
Py_DECREF(<object>self.value)
25
sage_free(self)
26
27
cdef void binary_tree_dealloc(binary_tree_node *self):
28
if self.left != NULL:
29
binary_tree_dealloc(self.left)
30
free_binary_tree_node(self.left)
31
if self.right != NULL:
32
binary_tree_dealloc(self.right)
33
free_binary_tree_node(self.right)
34
35
36
cdef void binary_tree_insert(binary_tree_node *self, int key, object value):
37
if self.key == key:
38
return
39
elif self.key > key:
40
if self.left == NULL:
41
self.left = BinaryTreeNode(key, value)
42
else:
43
binary_tree_insert(self.left, key, value)
44
else:
45
if self.right == NULL:
46
self.right = BinaryTreeNode(key, value)
47
else:
48
binary_tree_insert(self.right, key, value)
49
50
cdef object binary_tree_get(binary_tree_node *self, int key):
51
if self.key == key:
52
return <object>self.value
53
elif self.key > key:
54
if self.left == NULL:
55
return None
56
else:
57
return binary_tree_get(self.left, key)
58
else:
59
if self.right == NULL:
60
return None
61
else:
62
return binary_tree_get(self.right, key)
63
64
cdef object binary_tree_delete(binary_tree_node *self, int key):
65
cdef object t
66
cdef binary_tree_node *cur
67
if self.key > key:
68
if self.left == NULL:
69
return None
70
elif self.left.key == key:
71
t = <object>self.left.value
72
self.left = binary_tree_left_excise(self.left)
73
return t
74
else:
75
return binary_tree_delete(self.left, key)
76
else:
77
if self.right == NULL:
78
return None
79
elif self.right.key == key:
80
t = <object>self.right.value
81
self.right = binary_tree_right_excise(self.right)
82
return t
83
else:
84
return binary_tree_delete(self.right, key)
85
86
cdef binary_tree_node *binary_tree_left_excise(binary_tree_node *self):
87
cdef binary_tree_node *left, *cur
88
if self.left == NULL:
89
left = self.right
90
elif self.right == NULL:
91
left = self.left
92
else:
93
left = self.left
94
cur = self.right
95
while cur.right != NULL:
96
cur = cur.right
97
cur.right = self.left.right
98
free_binary_tree_node(self)
99
return left
100
101
102
103
cdef binary_tree_node *binary_tree_right_excise(binary_tree_node *self):
104
cdef binary_tree_node *right, *cur
105
if self.right == NULL:
106
right = self.left
107
elif self.left == NULL:
108
right = self.right
109
else:
110
right = self.right
111
cur = self.left
112
while cur.left != NULL:
113
cur = cur.left
114
cur.left = self.right.left
115
free_binary_tree_node(self)
116
return right
117
118
119
cdef binary_tree_node *binary_tree_head_excise(binary_tree_node *self):
120
cdef binary_tree_node *cur
121
cdef int right
122
# We have a pointer we're about to free. Chances are, we'll never
123
# see this pointer again. Thus, its least significant bit is
124
# "random" enough to resist bias.
125
right = (<int>self)&1
126
if self.right == NULL:
127
return self.left
128
if self.left == NULL:
129
return self.right
130
if right:
131
#move right branch to left, return left
132
cur = self.left
133
while cur.right != NULL:
134
cur = cur.right
135
cur.right = self.right
136
cur = self.left
137
else:
138
#move left branch to right, return right
139
cur = self.right
140
while cur.left != NULL:
141
cur = cur.left
142
cur.left = self.left
143
cur = self.right
144
free_binary_tree_node(self)
145
return cur
146
147
148
cdef int LIST_PREORDER, LIST_POSTORDER, LIST_INORDER, LIST_KEYS, LIST_VALUES
149
LIST_PREORDER = 1
150
LIST_INORDER = 2
151
LIST_POSTORDER = 4
152
LIST_KEYS = 8
153
LIST_VALUES = 16
154
155
cdef object binary_tree_list(binary_tree_node *cur, int behavior):
156
if behavior & LIST_KEYS:
157
item = int(cur.key)
158
else:
159
item = <object>cur.value
160
161
if behavior & LIST_PREORDER:
162
arry = [item]
163
else:
164
arry = []
165
166
if cur.left != NULL:
167
arry.extend(binary_tree_list(cur.left, behavior))
168
169
if behavior & LIST_INORDER:
170
arry.append(item)
171
172
if cur.right != NULL:
173
arry.extend(binary_tree_list(cur.right, behavior))
174
175
if behavior & LIST_POSTORDER:
176
arry.append(item)
177
178
return arry
179
180
181
182
cdef class BinaryTree:
183
"""
184
A simple binary tree with integer keys.
185
"""
186
def __init__(BinaryTree self):
187
self.head = NULL
188
def __dealloc__(BinaryTree self):
189
if self.head != NULL:
190
binary_tree_dealloc(self.head)
191
sage_free(self.head)
192
193
def insert(BinaryTree self, object key, object value = None):
194
"""
195
Inserts a key-value pair into the BinaryTree. Duplicate keys are ignored.
196
The first parameter, key, should be an int, or coercible (one-to-one) into an int.
197
198
EXAMPLES::
199
200
sage: from sage.misc.binary_tree import BinaryTree
201
sage: t = BinaryTree()
202
sage: t.insert(1)
203
sage: t.insert(0)
204
sage: t.insert(2)
205
sage: t.insert(0,1)
206
sage: t.get(0)
207
0
208
"""
209
cdef int ckey
210
if value is None:
211
value = key
212
ckey = int(key)
213
if self.head is NULL:
214
self.head = BinaryTreeNode(ckey, value)
215
else:
216
binary_tree_insert(self.head, ckey, value)
217
def delete(BinaryTree self, int key):
218
"""
219
Removes a the node corresponding to key, and returns the value
220
associated with it.
221
222
EXAMPLES::
223
224
sage: from sage.misc.binary_tree import BinaryTree
225
sage: t = BinaryTree()
226
sage: t.insert(3,3)
227
sage: t.insert(1,1)
228
sage: t.insert(2,2)
229
sage: t.insert(0,0)
230
sage: t.insert(5,5)
231
sage: t.insert(6,6)
232
sage: t.insert(4,4)
233
sage: t.delete(0)
234
0
235
sage: t.delete(3)
236
3
237
sage: t.delete(5)
238
5
239
sage: t.delete(2)
240
2
241
sage: t.delete(6)
242
6
243
sage: t.delete(1)
244
1
245
sage: t.delete(0)
246
sage: t.get_max()
247
4
248
sage: t.get_min()
249
4
250
"""
251
cdef object r
252
if self.head == NULL:
253
return None
254
elif self.head.key == key:
255
r = <object>self.head.value
256
self.head = binary_tree_head_excise(self.head)
257
return r
258
else:
259
return binary_tree_delete(self.head, key)
260
def get(BinaryTree self, int key):
261
"""
262
Returns the value associated with the key given.
263
264
EXAMPLES::
265
266
sage: from sage.misc.binary_tree import BinaryTree
267
sage: t = BinaryTree()
268
sage: t.insert(0,Matrix([[0,0],[1,1]]))
269
sage: t.insert(0,1)
270
sage: t.get(0)
271
[0 0]
272
[1 1]
273
"""
274
if self.head == NULL:
275
return None
276
else:
277
return binary_tree_get(self.head, key)
278
def contains(BinaryTree self, int key):
279
"""
280
Returns True if a node with the given key exists
281
in the tree, and False otherwise.
282
283
EXAMPLES::
284
285
sage: from sage.misc.binary_tree import BinaryTree
286
sage: t = BinaryTree()
287
sage: t.contains(1)
288
False
289
sage: t.insert(1,1)
290
sage: t.contains(1)
291
True
292
"""
293
if self.head == NULL:
294
return False
295
else:
296
if binary_tree_get(self.head, key) is not None:
297
return True
298
else:
299
return False
300
def get_max(BinaryTree self):
301
"""
302
Returns the value of the node with the maximal key value.
303
"""
304
cdef binary_tree_node *cur
305
if self.head == NULL:
306
return None
307
cur = self.head
308
while cur.right != NULL:
309
cur = cur.right
310
return <object>cur.value
311
def get_min(BinaryTree self):
312
"""
313
Returns the value of the node with the minimal key value.
314
"""
315
cdef binary_tree_node *cur
316
if self.head == NULL:
317
return None
318
cur = self.head
319
while cur.left != NULL:
320
cur = cur.left
321
return <object>cur.value
322
def pop_max(BinaryTree self):
323
"""
324
Returns the value of the node with the maximal key value,
325
and removes that node from the tree.
326
327
EXAMPLES::
328
329
sage: from sage.misc.binary_tree import BinaryTree
330
sage: t = BinaryTree()
331
sage: t.insert(4,'e')
332
sage: t.insert(2,'c')
333
sage: t.insert(0,'a')
334
sage: t.insert(1,'b')
335
sage: t.insert(3,'d')
336
sage: t.insert(5,'f')
337
sage: while not t.is_empty():
338
... print t.pop_max()
339
f
340
e
341
d
342
c
343
b
344
a
345
"""
346
cdef binary_tree_node *cur
347
cdef object max
348
if self.head == NULL:
349
return None
350
if self.head.right == NULL:
351
max = <object>self.head.value
352
cur = self.head.left
353
free_binary_tree_node(self.head)
354
self.head = cur
355
return max
356
cur = self.head
357
while cur.right.right != NULL:
358
cur = cur.right
359
max = <object>cur.right.value
360
cur.right = binary_tree_right_excise(cur.right)
361
return max
362
def pop_min(BinaryTree self):
363
"""
364
Returns the value of the node with the minimal key value,
365
and removes that node from the tree.
366
367
EXAMPLES::
368
369
sage: from sage.misc.binary_tree import BinaryTree
370
sage: t = BinaryTree()
371
sage: t.insert(4,'e')
372
sage: t.insert(2,'c')
373
sage: t.insert(0,'a')
374
sage: t.insert(1,'b')
375
sage: t.insert(3,'d')
376
sage: t.insert(5,'f')
377
sage: while not t.is_empty():
378
... print t.pop_min()
379
a
380
b
381
c
382
d
383
e
384
f
385
"""
386
cdef binary_tree_node *cur
387
cdef object min
388
if self.head == NULL:
389
return None
390
if self.head.left == NULL:
391
min = <object>self.head.value
392
cur = self.head.right
393
free_binary_tree_node(self.head)
394
self.head = cur
395
return min
396
cur = self.head
397
while cur.left.left != NULL:
398
cur = cur.left
399
min = <object>cur.left.value
400
cur.left = binary_tree_left_excise(cur.left)
401
return min
402
def is_empty(BinaryTree self):
403
"""
404
Returns True if the tree has no nodes.
405
406
EXAMPLES::
407
408
sage: from sage.misc.binary_tree import BinaryTree
409
sage: t = BinaryTree()
410
sage: t.is_empty()
411
True
412
sage: t.insert(0,0)
413
sage: t.is_empty()
414
False
415
"""
416
if self.head == NULL:
417
return True
418
else:
419
return False
420
421
def keys(BinaryTree self, order = "inorder"):
422
"""
423
Returns the keys sorted according to "order" parameter, which can be one of
424
"inorder", "preorder", or "postorder"
425
"""
426
if self.head == NULL:
427
return []
428
429
if order == "postorder": o = LIST_POSTORDER
430
elif order == "inorder": o = LIST_INORDER
431
else: o = LIST_PREORDER
432
433
return binary_tree_list(self.head, LIST_KEYS + o)
434
435
def values(BinaryTree self, order = "inorder"):
436
"""
437
Returns the keys sorted according to "order" parameter, which can be one of
438
"inorder", "preorder", or "postorder"
439
"""
440
if self.head == NULL:
441
return []
442
443
if order == "postorder": o = LIST_POSTORDER
444
elif order == "inorder": o = LIST_INORDER
445
else: o = LIST_PREORDER
446
447
return binary_tree_list(self.head, LIST_VALUES + o)
448
449
def _headkey_(BinaryTree self):
450
"""
451
Used by the stress tester. Don't think a user would care.
452
Email tom if you care what the headkey is.
453
"""
454
if self.head == NULL:
455
return 0
456
else:
457
return self.head.key
458
459
460
461
class Test:
462
def random(self):
463
self.binary_tree()
464
465
def binary_tree(self, values = 100, cycles = 100000):
466
"""
467
Performs a sequence of random operations, given random inputs
468
to stress test the binary tree structure. This was useful during
469
development to find memory leaks / segfaults. Cycles should be
470
at least 100 times as large as values, or the delete, contains,
471
and get methods won't hit very often.
472
473
INPUT:
474
475
- ``values`` -- number of possible values to use
476
477
- ``cycles`` -- number of operations to perform
478
479
TESTS::
480
481
sage: sage.misc.binary_tree.Test().random()
482
"""
483
from sage.misc.prandom import randint
484
t = BinaryTree()
485
for i in xrange(cycles):
486
r = randint(0,8)
487
s = randint(0,values)
488
if r==1:
489
t.insert(s)
490
elif r == 2:
491
t.delete(t._headkey_())
492
elif r == 3:
493
t.get(s)
494
elif r == 4:
495
t.contains(s)
496
elif r == 5:
497
t.get_max()
498
elif r == 6:
499
t.get_min()
500
elif r == 7:
501
t.pop_min()
502
elif r == 8:
503
t.pop_max()
504
else:
505
t.delete(s)
506
507