简单的treap
treap的确是比较简单的二叉树。虽然它不是平衡树,但是通过随机化生成的priority可以确保树不会太高。 treap应该是tree + heap得来的,tree是因为它是一个二叉树,heap则要求父节点的priority必须小于子树的priority( 这很像堆的特性)。又因为priority是随机生成的,所以可以通过随机化来减小树高。
treap也需要有旋转操作,当priority不满足的时候也需要进行旋转。删除某个节点的话,可以将这个节点的priority设置为infinity, 然后不断地下沉到叶子上,最后删除这个叶子就好了。但是因为涉及到旋转,所以插入和删除函数都是递归的。
def left_rotate(r: TreeNode, rl: TreeNode):
if r.priority <= rl.priority:
return r
r.left = rl.right
rl.right = r
return rl
def right_rotate(r: TreeNode, rr: TreeNode):
if r.priority <= rr.priority:
return r
r.right = rr.left
rr.left = r
return rr
def insert_tree_node(root: TreeNode, t: TreeNode):
if root is None:
return t
if t.val < root.val:
root.left = insert_tree_node(root.left, t)
root = left_rotate(root, root.left)
elif t.val > root.val:
root.right = insert_tree_node(root.right, t)
root = right_rotate(root, root.right)
else:
pass
return root
def delete_tree_node(root: TreeNode, val):
if root is None:
return None
if val < root.val:
root.left = delete_tree_node(root.left, val)
return root
elif val > root.val:
root.right = delete_tree_node(root.right, val)
return root
root.priority = 1 << 30 # mark this node priority as high enough
if root.left and ((root.right is None) or (root.left.priority < root.right.priority)):
root = left_rotate(root, root.left)
root.right = delete_tree_node(root.right, val)
elif root.right and ((root.left is None) or (root.left.priority >= root.right.priority)):
root = right_rotate(root, root.right)
root.left = delete_tree_node(root.left, val)
else: # left and right are None
assert root.left is None and root.right is None
return None
return root
同样为了看看插入节点和删除节点的变化,可以使用graphviz来做可视化。我们逆序插入1-12这些数值,然后删除1,2节点,看看每次变化。 因为priority是随机数,所以为了确保确定性,最好设置上随机数的种子。
def test_pprint_tree():
root = None
stream = StringIO()
random.seed(23)
N = 12
for val in range(N, 0, -1):
root = insert_tree_node(root, TreeNode(val))
# tree_to_dot(root, 'ins {}'.format(val), stream)
tree_to_dot(root, 'now', stream)
delete_tree_node(root, 1)
tree_to_dot(root, 'delete 1', stream)
delete_tree_node(root, 2)
tree_to_dot(root, 'delete 2', stream)
dot_to_graph('/tmp/example', stream.getvalue(), type='png')