|
2 | 2 | from typing import Tuple
|
3 | 3 |
|
4 | 4 |
|
5 |
| -class Node: |
| 5 | +class Node(object): |
6 | 6 | """
|
7 | 7 | Treap's node
|
8 |
| - Treap is a binary tree by key and heap by priority |
| 8 | + Treap is a binary tree by value and heap by priority |
9 | 9 | """
|
10 |
| - |
11 |
| - def __init__(self, key: int): |
12 |
| - self.key = key |
| 10 | + def __init__(self, value: int = None): |
| 11 | + self.value = value |
13 | 12 | self.prior = random()
|
14 |
| - self.l = None |
15 |
| - self.r = None |
| 13 | + self.left = None |
| 14 | + self.right = None |
16 | 15 |
|
| 16 | + def __repr__(self): |
| 17 | + from pprint import pformat |
17 | 18 |
|
18 |
| -def split(root: Node, key: int) -> Tuple[Node, Node]: |
| 19 | + if self.left is None and self.right is None: |
| 20 | + return "'%s: %.5s'" % (self.value, self.prior) |
| 21 | + else: |
| 22 | + return pformat( |
| 23 | + { |
| 24 | + "%s: %.5s" |
| 25 | + % (self.value, self.prior): (self.left, self.right) |
| 26 | + }, |
| 27 | + indent=1, |
| 28 | + ) |
| 29 | + |
| 30 | + def __str__(self): |
| 31 | + value = str(self.value) + " " |
| 32 | + left = str(self.left or "") |
| 33 | + right = str(self.right or "") |
| 34 | + return value + left + right |
| 35 | + |
| 36 | +def split(root: Node, value: int) -> Tuple[Node, Node]: |
19 | 37 | """
|
20 |
| - We split current tree into 2 trees with key: |
| 38 | + We split current tree into 2 trees with value: |
21 | 39 |
|
22 |
| - Left tree contains all keys less than split key. |
23 |
| - Right tree contains all keys greater or equal, than split key |
| 40 | + Left tree contains all values less than split value. |
| 41 | + Right tree contains all values greater or equal, than split value |
24 | 42 | """
|
25 | 43 | if root is None: # None tree is split into 2 Nones
|
26 | 44 | return (None, None)
|
27 |
| - if root.key >= key: |
28 |
| - """ |
29 |
| - Right tree's root will be current node. |
30 |
| - Now we split(with the same key) current node's left son |
31 |
| - Left tree: left part of that split |
32 |
| - Right tree's left son: right part of that split |
33 |
| - """ |
34 |
| - l, root.l = split(root.l, key) |
35 |
| - return (l, root) |
| 45 | + elif root.value is None: |
| 46 | + return (None, None) |
36 | 47 | else:
|
37 |
| - """ |
38 |
| - Just symmetric to previous case |
39 |
| - """ |
40 |
| - root.r, r = split(root.r, key) |
41 |
| - return (root, r) |
42 |
| - |
| 48 | + if value < root.value: |
| 49 | + """ |
| 50 | + Right tree's root will be current node. |
| 51 | + Now we split(with the same value) current node's left son |
| 52 | + Left tree: left part of that split |
| 53 | + Right tree's left son: right part of that split |
| 54 | + """ |
| 55 | + left, root.left = split(root.left, value) |
| 56 | + return (left, root) |
| 57 | + else: |
| 58 | + """ |
| 59 | + Just symmetric to previous case |
| 60 | + """ |
| 61 | + root.right, right = split(root.right, value) |
| 62 | + return (root, right) |
43 | 63 |
|
44 | 64 | def merge(left: Node, right: Node) -> Node:
|
45 | 65 | """
|
46 | 66 | We merge 2 trees into one.
|
47 |
| - Note: all left tree's keys must be less than all right tree's |
| 67 | + Note: all left tree's values must be less than all right tree's |
48 | 68 | """
|
49 |
| - if (not left) or (not right): |
50 |
| - """ |
51 |
| - If one node is None, return the other |
52 |
| - """ |
| 69 | + if (not left) or (not right): # If one node is None, return the other |
53 | 70 | return left or right
|
54 |
| - if left.key > right.key: |
| 71 | + elif left.prior < right.prior: |
55 | 72 | """
|
56 | 73 | Left will be root because it has more priority
|
57 | 74 | Now we need to merge left's right son and right tree
|
58 | 75 | """
|
59 |
| - left.r = merge(left.r, right) |
| 76 | + left.right = merge(left.right, right) |
60 | 77 | return left
|
61 | 78 | else:
|
62 | 79 | """
|
63 | 80 | Symmetric as well
|
64 | 81 | """
|
65 |
| - right.l = merge(left, right.l) |
| 82 | + right.left = merge(left, right.left) |
66 | 83 | return right
|
67 | 84 |
|
68 |
| - |
69 |
| -def insert(root: Node, key: int) -> Node: |
| 85 | +def insert(root: Node, value: int) -> Node: |
70 | 86 | """
|
71 | 87 | Insert element
|
72 | 88 |
|
73 |
| - Split current tree with a key into l, r, |
| 89 | + Split current tree with a value into left, right, |
74 | 90 | Insert new node into the middle
|
75 |
| - Merge l, node, r into root |
| 91 | + Merge left, node, right into root |
76 | 92 | """
|
77 |
| - node = Node(key) |
78 |
| - l, r = split(root, key) |
79 |
| - root = merge(l, node) |
80 |
| - root = merge(root, r) |
81 |
| - return root |
| 93 | + node = Node(value) |
| 94 | + left, right = split(root, value) |
| 95 | + return merge(merge(left, node), right) |
82 | 96 |
|
83 |
| - |
84 |
| -def erase(root: Node, key: int) -> Node: |
| 97 | +def erase(root: Node, value: int) -> Node: |
85 | 98 | """
|
86 | 99 | Erase element
|
87 | 100 |
|
88 |
| - Split all nodes with keys less into l, |
89 |
| - Split all nodes with keys greater into r. |
90 |
| - Merge l, r |
| 101 | + Split all nodes with values less into left, |
| 102 | + Split all nodes with values greater into right. |
| 103 | + Merge left, right |
91 | 104 | """
|
92 |
| - l, r = split(root, key) |
93 |
| - _, r = split(r, key + 1) |
94 |
| - return merge(l, r) |
95 |
| - |
| 105 | + left, right = split(root, value-1) |
| 106 | + _, right = split(right, value) |
| 107 | + return merge(left, right) |
96 | 108 |
|
97 |
| -def node_print(root: Node): |
| 109 | +def inorder(root: Node): |
98 | 110 | """
|
99 | 111 | Just recursive print of a tree
|
100 | 112 | """
|
101 |
| - if not root: |
| 113 | + if not root: # None |
102 | 114 | return
|
103 |
| - node_print(root.l) |
104 |
| - print(root.key, end=" ") |
105 |
| - node_print(root.r) |
| 115 | + else: |
| 116 | + inorder(root.left) |
| 117 | + print(root.value, end=" ") |
| 118 | + inorder(root.right) |
106 | 119 |
|
107 | 120 |
|
108 |
| -def interactTreap(): |
| 121 | +def interactTreap(root, args): |
109 | 122 | """
|
110 | 123 | Commands:
|
111 |
| - + key to add key into treap |
112 |
| - - key to erase all nodes with key |
113 |
| -
|
114 |
| - After each command, program prints treap |
| 124 | + + value to add value into treap |
| 125 | + - value to erase all nodes with value |
| 126 | +
|
| 127 | + >>> root = interactTreap(None, "+1") |
| 128 | + >>> inorder(root) |
| 129 | + 1 |
| 130 | + >>> root = interactTreap(root, "+3 +5 +17 +19 +2 +16 +4 +0") |
| 131 | + >>> inorder(root) |
| 132 | + 0 1 2 3 4 5 16 17 19 |
| 133 | + >>> root = interactTreap(root, "+4 +4 +4") |
| 134 | + >>> inorder(root) |
| 135 | + 0 1 2 3 4 4 4 4 5 16 17 19 |
| 136 | + >>> root = interactTreap(root, "-0") |
| 137 | + >>> inorder(root) |
| 138 | + 1 2 3 4 4 4 4 5 16 17 19 |
| 139 | + >>> root = interactTreap(root, "-4") |
| 140 | + >>> inorder(root) |
| 141 | + 1 2 3 5 16 17 19 |
| 142 | + >>> root = interactTreap(root, "=0") |
| 143 | + Unknown command |
115 | 144 | """
|
116 |
| - root = None |
117 |
| - while True: |
118 |
| - cmd = input().split() |
119 |
| - cmd[1] = int(cmd[1]) |
120 |
| - if cmd[0] == "+": |
121 |
| - root = insert(root, cmd[1]) |
122 |
| - elif cmd[0] == "-": |
123 |
| - root = erase(root, cmd[1]) |
| 145 | + for arg in args.split(): |
| 146 | + if arg[0] == "+": |
| 147 | + root = insert(root, int(arg[1:])) |
| 148 | + |
| 149 | + elif arg[0] == "-": |
| 150 | + root = erase(root, int(arg[1:])) |
| 151 | + |
124 | 152 | else:
|
125 | 153 | print("Unknown command")
|
126 |
| - node_print(root) |
127 | 154 |
|
| 155 | + return root |
| 156 | + |
| 157 | +def main(): |
| 158 | + """After each command, program prints treap""" |
| 159 | + root = None |
| 160 | + print("enter numbers to creat a tree, + value to add value into treap, - value to erase all nodes with value. 'q' to quit. ") |
| 161 | + |
| 162 | + args = input() |
| 163 | + while args != 'q': |
| 164 | + root = interactTreap(root, args) |
| 165 | + print(root) |
| 166 | + args = input() |
| 167 | + |
| 168 | + print("good by!") |
| 169 | + pass |
128 | 170 |
|
129 | 171 | if __name__ == "__main__":
|
130 |
| - interactTreap() |
| 172 | + import doctest |
| 173 | + doctest.testmod() |
| 174 | + main() |
0 commit comments