Update treap.py (#1358)

* Update treap.py

check merge()

* Update treap.py

random() is used. its difficult to write doctests
l->left
r->right
key->value
add __repr__ and __str__ in preorder
This commit is contained in:
Hocnonsense 2019-10-18 15:39:37 +08:00 committed by Christian Clauss
parent 7376addcd5
commit 179284a41b

View File

@ -2,129 +2,173 @@ from random import random
from typing import Tuple from typing import Tuple
class Node: class Node(object):
""" """
Treap's node Treap's node
Treap is a binary tree by key and heap by priority Treap is a binary tree by value and heap by priority
""" """
def __init__(self, value: int = None):
def __init__(self, key: int): self.value = value
self.key = key
self.prior = random() self.prior = random()
self.l = None self.left = None
self.r = None self.right = None
def __repr__(self):
from pprint import pformat
def split(root: Node, key: int) -> Tuple[Node, Node]: if self.left is None and self.right is None:
return "'%s: %.5s'" % (self.value, self.prior)
else:
return pformat(
{
"%s: %.5s"
% (self.value, self.prior): (self.left, self.right)
},
indent=1,
)
def __str__(self):
value = str(self.value) + " "
left = str(self.left or "")
right = str(self.right or "")
return value + left + right
def split(root: Node, value: int) -> Tuple[Node, Node]:
""" """
We split current tree into 2 trees with key: We split current tree into 2 trees with value:
Left tree contains all keys less than split key. Left tree contains all values less than split value.
Right tree contains all keys greater or equal, than split key Right tree contains all values greater or equal, than split value
""" """
if root is None: # None tree is split into 2 Nones if root is None: # None tree is split into 2 Nones
return (None, None) return (None, None)
if root.key >= key: elif root.value is None:
return (None, None)
else:
if value < root.value:
""" """
Right tree's root will be current node. Right tree's root will be current node.
Now we split(with the same key) current node's left son Now we split(with the same value) current node's left son
Left tree: left part of that split Left tree: left part of that split
Right tree's left son: right part of that split Right tree's left son: right part of that split
""" """
l, root.l = split(root.l, key) left, root.left = split(root.left, value)
return (l, root) return (left, root)
else: else:
""" """
Just symmetric to previous case Just symmetric to previous case
""" """
root.r, r = split(root.r, key) root.right, right = split(root.right, value)
return (root, r) return (root, right)
def merge(left: Node, right: Node) -> Node: def merge(left: Node, right: Node) -> Node:
""" """
We merge 2 trees into one. We merge 2 trees into one.
Note: all left tree's keys must be less than all right tree's Note: all left tree's values must be less than all right tree's
"""
if (not left) or (not right):
"""
If one node is None, return the other
""" """
if (not left) or (not right): # If one node is None, return the other
return left or right return left or right
if left.key > right.key: elif left.prior < right.prior:
""" """
Left will be root because it has more priority Left will be root because it has more priority
Now we need to merge left's right son and right tree Now we need to merge left's right son and right tree
""" """
left.r = merge(left.r, right) left.right = merge(left.right, right)
return left return left
else: else:
""" """
Symmetric as well Symmetric as well
""" """
right.l = merge(left, right.l) right.left = merge(left, right.left)
return right return right
def insert(root: Node, value: int) -> Node:
def insert(root: Node, key: int) -> Node:
""" """
Insert element Insert element
Split current tree with a key into l, r, Split current tree with a value into left, right,
Insert new node into the middle Insert new node into the middle
Merge l, node, r into root Merge left, node, right into root
""" """
node = Node(key) node = Node(value)
l, r = split(root, key) left, right = split(root, value)
root = merge(l, node) return merge(merge(left, node), right)
root = merge(root, r)
return root
def erase(root: Node, value: int) -> Node:
def erase(root: Node, key: int) -> Node:
""" """
Erase element Erase element
Split all nodes with keys less into l, Split all nodes with values less into left,
Split all nodes with keys greater into r. Split all nodes with values greater into right.
Merge l, r Merge left, right
""" """
l, r = split(root, key) left, right = split(root, value-1)
_, r = split(r, key + 1) _, right = split(right, value)
return merge(l, r) return merge(left, right)
def inorder(root: Node):
def node_print(root: Node):
""" """
Just recursive print of a tree Just recursive print of a tree
""" """
if not root: if not root: # None
return return
node_print(root.l) else:
print(root.key, end=" ") inorder(root.left)
node_print(root.r) print(root.value, end=" ")
inorder(root.right)
def interactTreap(): def interactTreap(root, args):
""" """
Commands: Commands:
+ key to add key into treap + value to add value into treap
- key to erase all nodes with key - value to erase all nodes with value
After each command, program prints treap >>> root = interactTreap(None, "+1")
>>> inorder(root)
1
>>> root = interactTreap(root, "+3 +5 +17 +19 +2 +16 +4 +0")
>>> inorder(root)
0 1 2 3 4 5 16 17 19
>>> root = interactTreap(root, "+4 +4 +4")
>>> inorder(root)
0 1 2 3 4 4 4 4 5 16 17 19
>>> root = interactTreap(root, "-0")
>>> inorder(root)
1 2 3 4 4 4 4 5 16 17 19
>>> root = interactTreap(root, "-4")
>>> inorder(root)
1 2 3 5 16 17 19
>>> root = interactTreap(root, "=0")
Unknown command
""" """
root = None for arg in args.split():
while True: if arg[0] == "+":
cmd = input().split() root = insert(root, int(arg[1:]))
cmd[1] = int(cmd[1])
if cmd[0] == "+": elif arg[0] == "-":
root = insert(root, cmd[1]) root = erase(root, int(arg[1:]))
elif cmd[0] == "-":
root = erase(root, cmd[1])
else: else:
print("Unknown command") print("Unknown command")
node_print(root)
return root
def main():
"""After each command, program prints treap"""
root = None
print("enter numbers to creat a tree, + value to add value into treap, - value to erase all nodes with value. 'q' to quit. ")
args = input()
while args != 'q':
root = interactTreap(root, args)
print(root)
args = input()
print("good by!")
pass
if __name__ == "__main__": if __name__ == "__main__":
interactTreap() import doctest
doctest.testmod()
main()