package com.jwetherell.algorithms.data_structures; import java.util.ArrayList; import java.util.List; /** * The treap and the randomized binary search tree are two closely related forms * of binary search tree data structures that maintain a dynamic set of ordered * values and allow binary searches among the values. After any sequence of * insertions and deletions of values, the shape of the tree is a random * variable with the same probability distribution as a random binary tree; in * particular, with high probability its height is proportional to the logarithm * of the number of values, so that each search, insertion, or deletion * operation takes logarithmic time to perform. * * http://en.wikipedia.org/wiki/Treap * * @author Justin Wetherell */ public class Treap> extends BinarySearchTree { private static int randomSeed = Integer.MAX_VALUE; // This should be at least twice the number of Nodes /** * Default constructor. */ public Treap() { this.creator = new BinarySearchTree.INodeCreator() { /** * {@inheritDoc} */ @Override public BinarySearchTree.Node createNewNode(BinarySearchTree.Node parent, T id) { return (new TreapNode(parent, id)); } }; } /** * Constructor with a random seed. * * @param randomSeed * to use as a random seed. */ public Treap(int randomSeed) { this(); Treap.randomSeed = randomSeed; } /** * Constructor with external Node creator. */ public Treap(INodeCreator creator) { super(creator); } /** * Constructor with external Node creator. */ public Treap(INodeCreator creator, int randomSeed) { this(randomSeed); this.creator = creator; } /** * {@inheritDoc} */ @Override protected Node addValue(T id) { Node nodeToReturn = super.addValue(id); TreapNode nodeToAdd = (TreapNode) nodeToReturn; heapify(nodeToAdd); return nodeToReturn; } /** * Heapify up the treap at the current node to the root. * * @param current * to heapify. */ private void heapify(TreapNode current) { // Bubble up the heap, if needed TreapNode parent = (TreapNode) current.parent; while (parent != null && current.priority > parent.priority) { Node grandParent = parent.parent; if (grandParent != null) { if (grandParent.greater != null && grandParent.greater == parent) { // My parent is my grandparents greater branch grandParent.greater = current; current.parent = grandParent; } else if (grandParent.lesser != null && grandParent.lesser == parent) { // My parent is my grandparents lesser branch grandParent.lesser = current; current.parent = grandParent; } else { throw new RuntimeException("YIKES! Grandparent should have at least one non-NULL child which should be my parent."); } current.parent = grandParent; } else { root = current; root.parent = null; } if (parent.lesser != null && parent.lesser == current) { // LEFT parent.lesser = null; if (current.greater == null) { current.greater = parent; parent.parent = current; } else { Node lost = current.greater; current.greater = parent; parent.parent = current; parent.lesser = lost; lost.parent = parent; } } else if (parent.greater != null && parent.greater == current) { // RIGHT parent.greater = null; if (current.lesser == null) { current.lesser = parent; parent.parent = current; } else { Node lost = current.lesser; current.lesser = parent; parent.parent = current; parent.greater = lost; lost.parent = parent; } } else { // We really shouldn't get here throw new RuntimeException("YIKES! Parent should have at least one non-NULL child which should be me."); } parent = (TreapNode) current.parent; } } /** * {@inheritDoc} */ @Override public String toString() { return TreapPrinter.getString(this); } private static class TreapNode> extends Node { private int priority = Integer.MIN_VALUE; private TreapNode(Node parent, int priority, T value) { super(parent, value); this.priority = priority; } private TreapNode(Node parent, T value) { this(parent, RANDOM.nextInt(randomSeed), value); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("priorty=").append(priority).append(" value=").append(id); if (parent != null) builder.append(" parent=").append(parent.id); builder.append("\n"); if (lesser != null) builder.append("left=").append(lesser.toString()).append("\n"); if (greater != null) builder.append("right=").append(greater.toString()).append("\n"); return builder.toString(); } } protected static class TreapPrinter { public static > String getString(Treap tree) { if (tree.root == null) return "Tree has no nodes."; return getString((TreapNode) tree.root, "", true); } private static > String getString(TreapNode node, String prefix, boolean isTail) { StringBuilder builder = new StringBuilder(); builder.append(prefix + (isTail ? "└── " : "├── ") + "(" + node.priority + ") " + node.id + "\n"); List> children = null; if (node.lesser != null || node.greater != null) { children = new ArrayList>(2); if (node.lesser != null) children.add(node.lesser); if (node.greater != null) children.add(node.greater); } if (children != null) { for (int i = 0; i < children.size() - 1; i++) { TreapNode treapNode = (TreapNode) children.get(i); builder.append(getString(treapNode, prefix + (isTail ? " " : "│ "), false)); } if (children.size() >= 1) { TreapNode treapNode = (TreapNode) children.get(children.size() - 1); builder.append(getString(treapNode, prefix + (isTail ? " " : "│ "), true)); } } return builder.toString(); } } }