Full Code of ignl/BinarySearchTrees for AI

master 965006a43fea cached
41 files
129.1 KB
32.3k tokens
248 symbols
1 requests
Download .txt
Repository: ignl/BinarySearchTrees
Branch: master
Commit: 965006a43fea
Files: 41
Total size: 129.1 KB

Directory structure:
gitextract_wjyganpj/

├── .gitignore
├── LICENSE
├── README.md
└── Trees/
    ├── .gitignore
    ├── pom.xml
    └── src/
        ├── main/
        │   └── java/
        │       └── org/
        │           └── intelligentjava/
        │               └── algos/
        │                   ├── simplestructures/
        │                   │   ├── LinkedList.java
        │                   │   ├── PriorityQueue.java
        │                   │   ├── Queue.java
        │                   │   └── Stack.java
        │                   └── trees/
        │                       ├── AVLTree.java
        │                       ├── AbstractBinarySearchTree.java
        │                       ├── AbstractSelfBalancingBinarySearchTree.java
        │                       ├── BinarySearchTree.java
        │                       ├── RedBlackTree.java
        │                       ├── ScapegoatTree.java
        │                       ├── SplayTree.java
        │                       ├── Treap.java
        │                       ├── benchmark/
        │                       │   ├── TreesDeleteBenchmark.java
        │                       │   ├── TreesInsertRandomBenchmark.java
        │                       │   ├── TreesInsertSortedBenchmark.java
        │                       │   ├── TreesSearchBenchmark.java
        │                       │   └── TreesSearchSameElementsBenchmark.java
        │                       ├── exceptions/
        │                       │   └── QueueOverflowException.java
        │                       ├── main/
        │                       │   └── Main.java
        │                       └── utils/
        │                           ├── ArrayUtils.java
        │                           ├── HeapUtils.java
        │                           └── MathUtils.java
        └── test/
            └── java/
                └── org/
                    └── intelligentjava/
                        └── algos/
                            ├── simplestructures/
                            │   ├── LinkedListTest.java
                            │   ├── PriorityQueueTest.java
                            │   ├── QueueTest.java
                            │   └── StackTest.java
                            └── trees/
                                ├── AVLTreeTest.java
                                ├── BaseBSTTest.java
                                ├── BinarySearchTreeTest.java
                                ├── RedBlackTreeTest.java
                                ├── ScapegoatTreeTest.java
                                ├── SplayTreeTest.java
                                ├── TreapTest.java
                                └── utils/
                                    ├── ArrayUtilsTest.java
                                    ├── HeapUtilsTest.java
                                    └── MathUtilsTest.java

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
Trees/.classpath
Trees/.project
Trees/.settings/org.eclipse.jdt.core.prefs
Trees/.settings/org.eclipse.m2e.core.prefs


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# BinarySearchTrees
Java binary search trees implementations and tests: AVL Tree, Red black tree, Scapegoat tree, Splay tree, Treap

Blog post and benchmarks: https://intelligentjava.wordpress.com/2015/04/09/self-balancing-binary-search-trees-comparison/

To run benchmarks:  
cd Trees  
mvn clean install  
java -jar target/benchmarks.jar  


================================================
FILE: Trees/.gitignore
================================================
/target/


================================================
FILE: Trees/pom.xml
================================================
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.intelligentjava</groupId>
  <artifactId>Trees</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>

		<!-- Microbenchmark -->
		<dependency>
			<groupId>org.openjdk.jmh</groupId>
			<artifactId>jmh-core</artifactId>
			<version>1.21</version>
		</dependency>

		<dependency>
			<groupId>org.openjdk.jmh</groupId>
			<artifactId>jmh-generator-annprocess</artifactId>
			<version>1.21</version>
			<!-- the processor artifact is required only during compilation and does 
				not need to be transitive, hence provided scope -->
			<scope>provided</scope>
		</dependency>

		<!-- Testing -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
		</dependency>
	</dependencies>
	
	<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <compilerVersion>1.7</compilerVersion>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.2</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <finalName>benchmarks</finalName>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>org.openjdk.jmh.Main</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>2.5</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>2.4</version>
                </plugin>
                <plugin>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <version>2.9.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>2.6</version>
                </plugin>
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.3</version>
                </plugin>
                <plugin>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>2.2.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.17</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
  
</project>

================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/LinkedList.java
================================================
package org.intelligentjava.algos.simplestructures;

/**
 * Standard simple non circular doubly linked Linked List implementation.
 * 
 * @author Ignas Lelys
 * @created May 4, 2011
 *
 */
// TODO iterator
public class LinkedList {
    
    private Entry head;
    
    // TODO error checking
    public int get(int index) {
        Entry entry = head;
        for (int i = 0; i < index; i++) {
            entry = entry.next;
        }
        return entry.element;
    }
    
    public void insert(int element) {
        Entry oldHead = this.head;
        this.head = new Entry(null, oldHead, element);
        if (oldHead != null) {
            oldHead.previous = head;
        }
    }
    
    public void delete(int element) {
        Entry elementEntry = search(element);
        if (elementEntry != null) {
            if (elementEntry.previous != null) {
                elementEntry.previous.next = elementEntry.next;
            } else {
                this.head = elementEntry.next; // if no previous, that means we are deleting head
            }
            if (elementEntry.next != null) {
                elementEntry.next.previous = elementEntry.previous;
            }
        }
    }
    
    private Entry search(int key) {
        Entry entry = head;
        while (entry != null) {
            if (entry.element == key) {
                return entry;
            }
            entry = entry.next;
        }
        return null;
    }
    
    private static class Entry {
        public Entry(Entry previous, Entry next, int element) {
            super();
            this.previous = previous;
            this.next = next;
            this.element = element;
        }
        public Entry previous;
        public Entry next;
        public int element;
    }
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/PriorityQueue.java
================================================
package org.intelligentjava.algos.simplestructures;

import org.intelligentjava.algos.trees.utils.ArrayUtils;
import org.intelligentjava.algos.trees.utils.HeapUtils;

/**
 * Priority queue implementation.
 * 
 * @author Ignas Lelys
 * @created Apr 18, 2011
 * 
 */
public class PriorityQueue {

    private int[] heap;

    private int heapSize = 0;

    public PriorityQueue() {
        heap = new int[100];
    }

    public void insertElement(int element) {
        heapSize++;
        heap[heapSize - 1] = Integer.MIN_VALUE;
        changeElementValue(heapSize - 1, element);
    }

    public void changeElementValue(int index, int newValue) {
        if (heap[index] > newValue) {
            throw new RuntimeException("New value is smaller than old one.");
        }
        heap[index] = newValue;
        while (index > 0 && heap[HeapUtils.getParent(index)] < heap[index]) {
            ArrayUtils.swap(heap, index, HeapUtils.getParent(index));
            index = HeapUtils.getParent(index);
        }
    }

    public int getElement() {
        return heap[0];
    }

    public int removeElement() {
        if (heapSize < 1) {
            throw new RuntimeException();
        }
        int maxElement = heap[0];
        heap[0] = heap[heapSize - 1];
        heapSize--;
        HeapUtils.maxHeapify(heap, 0, heapSize);
        return maxElement;
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/Queue.java
================================================
package org.intelligentjava.algos.simplestructures;

import org.intelligentjava.algos.trees.exceptions.QueueOverflowException;

/**
 * Simple queue.
 * 
 * @author Ignas Lelys
 * @created May 4, 2011
 * 
 */
public class Queue {

    private Object[] queue;

    private int head = 0;

    private int tail = 0;

    public Queue() {
        super();
        queue = new Object[10];
    }

    public Queue(int queueSize) {
        super();
        queue = new Object[queueSize];
    }

    public void enqueue(Object element) throws QueueOverflowException {
        if (isFull()) {
            throw new QueueOverflowException();
        }
        queue[tail] = element;
        if (tail == queue.length - 1) {
            tail = 0;
        } else {
            tail++;
        }
    }

    public Object dequeue() {
        Object element = queue[head];
        if (head == queue.length - 1) {
            head = 0;
        } else {
            head++;
        }
        return element;
    }

    public boolean isEmpty() {
        return head == tail;
    }
    
    public boolean isFull() {
        int nextTailValue = tail;
        if (nextTailValue == queue.length - 1) {
            nextTailValue = 0;
        } else {
            nextTailValue++;
        }
        if (head == nextTailValue) {
            return true;
        } else {
            return false;
        }
    }
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/Stack.java
================================================
package org.intelligentjava.algos.simplestructures;

import java.util.Arrays;

/**
 * Stack.
 * 
 * @author Ignas Lelys
 * @created May 4, 2011
 *
 */
public class Stack {
    
    private Object[] elements;
    
    private int top = 0;
    
    public Stack() {
        super();
        elements = new Object[10];
    }
    
    public Stack(int initialSize) {
        super();
        elements = new Object[initialSize];
    }

    public boolean isEmpty() {
        return top == 0;
    }
    
    public void push(Object element) {
        if (top == elements.length) {
            elements = Arrays.copyOf(elements, elements.length + 10);
        }
        elements[top] = element;
        top++;
    }
    
    public Object pop() {
        if (!isEmpty()) {
            return elements[--top];
        }
        return null;
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AVLTree.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.utils.MathUtils;

/**
 * AVL tree implementation.
 * 
 * In computer science, an AVL tree is a self-balancing binary search tree, and
 * it was the first such data structure to be invented.[1] In an AVL tree, the
 * heights of the two child subtrees of any node differ by at most one. Lookup,
 * insertion, and deletion all take O(log n) time in both the average and worst
 * cases, where n is the number of nodes in the tree prior to the operation.
 * Insertions and deletions may require the tree to be rebalanced by one or more
 * tree rotations.
 * 
 * @author Ignas Lelys
 * @created Jun 28, 2011
 * 
 */
public class AVLTree extends AbstractSelfBalancingBinarySearchTree {

    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#insert(int)
     * 
     *      AVL tree insert method also balances tree if needed. Additional
     *      height parameter on node is used to track if one subtree is higher
     *      than other by more than one, if so AVL tree rotations is performed
     *      to regain balance of the tree.
     */
    @Override
    public Node insert(int element) {
        Node newNode = super.insert(element);
        rebalance((AVLNode)newNode);
        return newNode;
    }

    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#delete(int)
     */
    @Override
    public Node delete(int element) {
        Node deleteNode = super.search(element);
        if (deleteNode != null) {
            Node successorNode = super.delete(deleteNode);
            if (successorNode != null) {
                // if replaced from getMinimum(deleteNode.right) then come back there and update heights
                AVLNode minimum = successorNode.right != null ? (AVLNode)getMinimum(successorNode.right) : (AVLNode)successorNode;
                recomputeHeight(minimum);
                rebalance((AVLNode)minimum);
            } else {
                recomputeHeight((AVLNode)deleteNode.parent);
                rebalance((AVLNode)deleteNode.parent);
            }
            return successorNode;
        }
        return null;
    }
    
    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#createNode(int, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node)
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new AVLNode(value, parent, left, right);
    }

    /**
     * Go up from inserted node, and update height and balance informations if needed.
     * If some node balance reaches 2 or -2 that means that subtree must be rebalanced.
     * 
     * @param node Inserted Node.
     */
    private void rebalance(AVLNode node) {
        while (node != null) {
            
            Node parent = node.parent;
            
            int leftHeight = (node.left == null) ? -1 : ((AVLNode) node.left).height;
            int rightHeight = (node.right == null) ? -1 : ((AVLNode) node.right).height;
            int nodeBalance = rightHeight - leftHeight;
            // rebalance (-2 means left subtree outgrow, 2 means right subtree)
            if (nodeBalance == 2) {
                if (node.right.right != null) {
                    node = (AVLNode)avlRotateLeft(node);
                    break;
                } else {
                    node = (AVLNode)doubleRotateRightLeft(node);
                    break;
                }
            } else if (nodeBalance == -2) {
                if (node.left.left != null) {
                    node = (AVLNode)avlRotateRight(node);
                    break;
                } else {
                    node = (AVLNode)doubleRotateLeftRight(node);
                    break;
                }
            } else {
                updateHeight(node);
            }
            
            node = (AVLNode)parent;
        }
    }

    /**
     * Rotates to left side.
     */
    private Node avlRotateLeft(Node node) {
        Node temp = super.rotateLeft(node);
        
        updateHeight((AVLNode)temp.left);
        updateHeight((AVLNode)temp);
        return temp;
    }

    /**
     * Rotates to right side.
     */
    private Node avlRotateRight(Node node) {
        Node temp = super.rotateRight(node);

        updateHeight((AVLNode)temp.right);
        updateHeight((AVLNode)temp);
        return temp;
    }

    /**
     * Take right child and rotate it to the right side first and then rotate
     * node to the left side.
     */
    protected Node doubleRotateRightLeft(Node node) {
        node.right = avlRotateRight(node.right);
        return avlRotateLeft(node);
    }

    /**
     * Take right child and rotate it to the right side first and then rotate
     * node to the left side.
     */
    protected Node doubleRotateLeftRight(Node node) {
        node.left = avlRotateLeft(node.left);
        return avlRotateRight(node);
    }
    
    /**
     * Recomputes height information from the node and up for all of parents. It needs to be done after delete.
     */
    private void recomputeHeight(AVLNode node) {
       while (node != null) {
          node.height = maxHeight((AVLNode)node.left, (AVLNode)node.right) + 1;
          node = (AVLNode)node.parent;
       }
    }
    
    /**
     * Returns higher height of 2 nodes. 
     */
    private int maxHeight(AVLNode node1, AVLNode node2) {
        if (node1 != null && node2 != null) {
            return node1.height > node2.height ? node1.height : node2.height;
        } else if (node1 == null) {
            return node2 != null ? node2.height : -1;
        } else if (node2 == null) {
            return node1 != null ? node1.height : -1;
        }
        return -1;
    }

    /**
     * Updates height and balance of the node.
     * 
     * @param node Node for which height and balance must be updated.
     */
    private static final void updateHeight(AVLNode node) {
        int leftHeight = (node.left == null) ? -1 : ((AVLNode) node.left).height;
        int rightHeight = (node.right == null) ? -1 : ((AVLNode) node.right).height;
        node.height = 1 + MathUtils.getMax(leftHeight, rightHeight);
    }

    /**
     * Node of AVL tree has height and balance additional properties. If balance
     * equals 2 (or -2) that node needs to be re balanced. (Height is height of
     * the subtree starting with this node, and balance is difference between
     * left and right nodes heights).
     * 
     * @author Ignas Lelys
     * @created Jun 30, 2011
     * 
     */
    protected static class AVLNode extends Node {
        public int height;

        public AVLNode(int value, Node parent, Node left, Node right) {
            super(value, parent, left, right);
        }
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AbstractBinarySearchTree.java
================================================
package org.intelligentjava.algos.trees;

/**
 * Abstract binary search tree implementation. Its basically fully implemented
 * binary search tree, just template method is provided for creating Node (other
 * trees can have slightly different nodes with more info). This way some code
 * from standart binary search tree can be reused for other kinds of binary
 * trees.
 * 
 * @author Ignas Lelys
 * @created Jun 29, 2011
 * 
 */
public abstract class AbstractBinarySearchTree {

    /** Root node where whole tree starts. */
    public Node root;

    /** Tree size. */
    protected int size;

    /**
     * Because this is abstract class and various trees have different additional information on 
     * different nodes subclasses uses this abstract method to create nodes (maybe of class {@link Node}
     * or maybe some different node sub class).
     * 
     * @param value Value that node will have.
     * @param parent Node's parent.
     * @param left Node's left child.
     * @param right Node's right child.
     * @return Created node instance.
     */
    protected abstract Node createNode(int value, Node parent, Node left, Node right);

    /**
     * Finds a node with concrete value. If it is not found then null is
     * returned.
     * 
     * @param element
     *            Element value.
     * @return Node with value provided, or null if not found.
     */
    public Node search(int element) {
        Node node = root;
        while (node != null && node.value != null && node.value != element) {
            if (element < node.value) {
                node = node.left;
            } else {
                node = node.right;
            }
        }
        return node;
    }

    /**
     * Insert new element to tree.
     * 
     * @param element
     *            Element to insert.
     */
    public Node insert(int element) {
        if (root == null) {
            root = createNode(element, null, null, null);
            size++;
            return root;
        }

        Node insertParentNode = null;
        Node searchTempNode = root;
        while (searchTempNode != null && searchTempNode.value != null) {
            insertParentNode = searchTempNode;
            if (element < searchTempNode.value) {
                searchTempNode = searchTempNode.left;
            } else {
                searchTempNode = searchTempNode.right;
            }
        }

        Node newNode = createNode(element, insertParentNode, null, null);
        if (insertParentNode.value > newNode.value) {
            insertParentNode.left = newNode;
        } else {
            insertParentNode.right = newNode;
        }

        size++;
        return newNode;
    }

    /**
     * Removes element if node with such value exists.
     * 
     * @param element
     *            Element value to remove.
     * 
     * @return New node that is in place of deleted node. Or null if element for
     *         delete was not found.
     */
    public Node delete(int element) {
        Node deleteNode = search(element);
        if (deleteNode != null) {
            return delete(deleteNode);
        } else {
            return null;
        }
    }

    /**
     * Delete logic when node is already found.
     * 
     * @param deleteNode
     *            Node that needs to be deleted.
     * 
     * @return New node that is in place of deleted node. Or null if element for
     *         delete was not found.
     */
    protected Node delete(Node deleteNode) {
        if (deleteNode != null) {
            Node nodeToReturn = null;
            if (deleteNode != null) {
                if (deleteNode.left == null) {
                    nodeToReturn = transplant(deleteNode, deleteNode.right);
                } else if (deleteNode.right == null) {
                    nodeToReturn = transplant(deleteNode, deleteNode.left);
                } else {
                    Node successorNode = getMinimum(deleteNode.right);
                    if (successorNode.parent != deleteNode) {
                        transplant(successorNode, successorNode.right);
                        successorNode.right = deleteNode.right;
                        successorNode.right.parent = successorNode;
                    }
                    transplant(deleteNode, successorNode);
                    successorNode.left = deleteNode.left;
                    successorNode.left.parent = successorNode;
                    nodeToReturn = successorNode;
                }
                size--;
            }
    
            return nodeToReturn;
        }
        return null;
    }

    /**
     * Put one node from tree (newNode) to the place of another (nodeToReplace).
     * 
     * @param nodeToReplace
     *            Node which is replaced by newNode and removed from tree.
     * @param newNode
     *            New node.
     * 
     * @return New replaced node.
     */
    private Node transplant(Node nodeToReplace, Node newNode) {
        if (nodeToReplace.parent == null) {
            this.root = newNode;
        } else if (nodeToReplace == nodeToReplace.parent.left) {
            nodeToReplace.parent.left = newNode;
        } else {
            nodeToReplace.parent.right = newNode;
        }
        if (newNode != null) {
            newNode.parent = nodeToReplace.parent;
        }
        return newNode;
    }

    /**
     * @param element
     * @return true if tree contains element.
     */
    public boolean contains(int element) {
        return search(element) != null;
    }

    /**
     * @return Minimum element in tree.
     */
    public int getMinimum() {
        return getMinimum(root).value;
    }

    /**
     * @return Maximum element in tree.
     */
    public int getMaximum() {
        return getMaximum(root).value;
    }

    /**
     * Get next element element who is bigger than provided element.
     * 
     * @param element
     *            Element for whom descendand element is searched
     * @return Successor value.
     */
    // TODO Predecessor
    public int getSuccessor(int element) {
        return getSuccessor(search(element)).value;
    }

    /**
     * @return Number of elements in the tree.
     */
    public int getSize() {
        return size;
    }

    /**
     * Tree traversal with printing element values. In order method.
     */
    public void printTreeInOrder() {
        printTreeInOrder(root);
    }

    /**
     * Tree traversal with printing element values. Pre order method.
     */
    public void printTreePreOrder() {
        printTreePreOrder(root);
    }

    /**
     * Tree traversal with printing element values. Post order method.
     */
    public void printTreePostOrder() {
        printTreePostOrder(root);
    }

    /*-------------------PRIVATE HELPER METHODS-------------------*/

    private void printTreeInOrder(Node entry) {
        if (entry != null) {
            printTreeInOrder(entry.left);
            if (entry.value != null) {
                System.out.println(entry.value);
            }
            printTreeInOrder(entry.right);
        }
    }

    private void printTreePreOrder(Node entry) {
        if (entry != null) {
            if (entry.value != null) {
                System.out.println(entry.value);
            }
            printTreeInOrder(entry.left);
            printTreeInOrder(entry.right);
        }
    }

    private void printTreePostOrder(Node entry) {
        if (entry != null) {
            printTreeInOrder(entry.left);
            printTreeInOrder(entry.right);
            if (entry.value != null) {
                System.out.println(entry.value);
            }
        }
    }

    protected Node getMinimum(Node node) {
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

    protected Node getMaximum(Node node) {
        while (node.right != null) {
            node = node.right;
        }
        return node;
    }

    protected Node getSuccessor(Node node) {
        // if there is right branch, then successor is leftmost node of that
        // subtree
        if (node.right != null) {
            return getMinimum(node.right);
        } else { // otherwise it is a lowest ancestor whose left child is also
            // ancestor of node
            Node currentNode = node;
            Node parentNode = node.parent;
            while (parentNode != null && currentNode == parentNode.right) {
                // go up until we find parent that currentNode is not in right
                // subtree.
                currentNode = parentNode;
                parentNode = parentNode.parent;
            }
            return parentNode;
        }
    }
    
    //-------------------------------- TREE PRINTING ------------------------------------

    public void printTree() {
        printSubtree(root);
    }
    
    public void printSubtree(Node node) {
        if (node.right != null) {
            printTree(node.right, true, "");
        }
        printNodeValue(node);
        if (node.left != null) {
            printTree(node.left, false, "");
        }
    }
    
    private void printNodeValue(Node node) {
        if (node.value == null) {
            System.out.print("<null>");
        } else {
            System.out.print(node.value.toString());
        }
        System.out.println();
    }
    
    private void printTree(Node node, boolean isRight, String indent) {
        if (node.right != null) {
            printTree(node.right, true, indent + (isRight ? "        " : " |      "));
        }
        System.out.print(indent);
        if (isRight) {
            System.out.print(" /");
        } else {
            System.out.print(" \\");
        }
        System.out.print("----- ");
        printNodeValue(node);
        if (node.left != null) {
            printTree(node.left, false, indent + (isRight ? " |      " : "        "));
        }
    }


    public static class Node {
        public Node(Integer value, Node parent, Node left, Node right) {
            super();
            this.value = value;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }

        public Integer value;
        public Node parent;
        public Node left;
        public Node right;
        
        public boolean isLeaf() {
            return left == null && right == null;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((value == null) ? 0 : value.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Node other = (Node) obj;
            if (value == null) {
                if (other.value != null)
                    return false;
            } else if (!value.equals(other.value))
                return false;
            return true;
        }

    }
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AbstractSelfBalancingBinarySearchTree.java
================================================
package org.intelligentjava.algos.trees;

/**
 * Abstract class for self balancing binary search trees. Contains some methods
 * that is used for self balancing trees.
 * 
 * @author Ignas Lelys
 * @created Jul 24, 2011
 * 
 */
public abstract class AbstractSelfBalancingBinarySearchTree extends AbstractBinarySearchTree {

    /**
     * Rotate to the left.
     * 
     * @param node Node on which to rotate.
     * @return Node that is in place of provided node after rotation.
     */
    protected Node rotateLeft(Node node) {
        Node temp = node.right;
        temp.parent = node.parent;

        node.right = temp.left;
        if (node.right != null) {
            node.right.parent = node;
        }

        temp.left = node;
        node.parent = temp;

        // temp took over node's place so now its parent should point to temp
        if (temp.parent != null) {
            if (node == temp.parent.left) {
                temp.parent.left = temp;
            } else {
                temp.parent.right = temp;
            }
        } else {
            root = temp;
        }
        
        return temp;
    }

    /**
     * Rotate to the right.
     * 
     * @param node Node on which to rotate.
     * @return Node that is in place of provided node after rotation.
     */
    protected Node rotateRight(Node node) {
        Node temp = node.left;
        temp.parent = node.parent;

        node.left = temp.right;
        if (node.left != null) {
            node.left.parent = node;
        }

        temp.right = node;
        node.parent = temp;

        // temp took over node's place so now its parent should point to temp
        if (temp.parent != null) {
            if (node == temp.parent.left) {
                temp.parent.left = temp;
            } else {
                temp.parent.right = temp;
            }
        } else {
            root = temp;
        }
        
        return temp;
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/BinarySearchTree.java
================================================
package org.intelligentjava.algos.trees;

/**
 * Binary search tree implementation.
 * 
 * In computer science, a binary search tree (BST), which may sometimes also be
 * called an ordered or sorted binary tree, is a node-based binary tree data
 * structure which has the following properties:
 * 
 * a) The left subtree of a node contains only nodes with keys less than the node's key. </br>
 * b) The right subtree of a node contains only nodes with keys greater than the node's key. </br>
 * c) Both the left and right subtrees must also be binary search trees. </br>
 * 
 * @author Ignas Lelys
 * @created May 6, 2011
 * 
 */
public class BinarySearchTree extends AbstractBinarySearchTree {

    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new Node(value, parent, left, right);
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/RedBlackTree.java
================================================
package org.intelligentjava.algos.trees;

/**
 * Red-Black tree implementation. From Introduction to Algorithms 3rd edition.
 * 
 * @author Ignas Lelys
 * @created May 6, 2011
 * 
 */
public class RedBlackTree extends AbstractSelfBalancingBinarySearchTree {

    protected enum ColorEnum {
        RED,
        BLACK
    };

    protected static final RedBlackNode nilNode = new RedBlackNode(null, null, null, null, ColorEnum.BLACK);

    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#insert(int)
     */
    @Override
    public Node insert(int element) {
        Node newNode = super.insert(element);
        newNode.left = nilNode;
        newNode.right = nilNode;
        root.parent = nilNode;
        insertRBFixup((RedBlackNode) newNode);
        return newNode;
    }
    
    /**
     * Slightly modified delete routine for red-black tree.
     * 
     * {@inheritDoc}
     */
    @Override
    protected Node delete(Node deleteNode) {
        Node replaceNode = null; // track node that replaces removedOrMovedNode
        if (deleteNode != null && deleteNode != nilNode) {
            Node removedOrMovedNode = deleteNode; // same as deleteNode if it has only one child, and otherwise it replaces deleteNode
            ColorEnum removedOrMovedNodeColor = ((RedBlackNode)removedOrMovedNode).color;
        
            if (deleteNode.left == nilNode) {
                replaceNode = deleteNode.right;
                rbTreeTransplant(deleteNode, deleteNode.right);
            } else if (deleteNode.right == nilNode) {
                replaceNode = deleteNode.left;
                rbTreeTransplant(deleteNode, deleteNode.left);
            } else {
                removedOrMovedNode = getMinimum(deleteNode.right);
                removedOrMovedNodeColor = ((RedBlackNode)removedOrMovedNode).color;
                replaceNode = removedOrMovedNode.right;
                if (removedOrMovedNode.parent == deleteNode) {
                    replaceNode.parent = removedOrMovedNode;
                } else {
                    rbTreeTransplant(removedOrMovedNode, removedOrMovedNode.right);
                    removedOrMovedNode.right = deleteNode.right;
                    removedOrMovedNode.right.parent = removedOrMovedNode;
                }
                rbTreeTransplant(deleteNode, removedOrMovedNode);
                removedOrMovedNode.left = deleteNode.left;
                removedOrMovedNode.left.parent = removedOrMovedNode;
                ((RedBlackNode)removedOrMovedNode).color = ((RedBlackNode)deleteNode).color;
            }
            
            size--;
            if (removedOrMovedNodeColor == ColorEnum.BLACK) {
                deleteRBFixup((RedBlackNode)replaceNode);
            }
        }
        
        return replaceNode;
    }
    
    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#createNode(int, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node)
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new RedBlackNode(value, parent, left, right, ColorEnum.RED);
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected Node getMinimum(Node node) {
        while (node.left != nilNode) {
            node = node.left;
        }
        return node;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Node getMaximum(Node node) {
        while (node.right != nilNode) {
            node = node.right;
        }
        return node;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected Node rotateLeft(Node node) {
        Node temp = node.right;
        temp.parent = node.parent;
        
        node.right = temp.left;
        if (node.right != nilNode) {
            node.right.parent = node;
        }

        temp.left = node;
        node.parent = temp;

        // temp took over node's place so now its parent should point to temp
        if (temp.parent != nilNode) {
            if (node == temp.parent.left) {
                temp.parent.left = temp;
            } else {
                temp.parent.right = temp;
            }
        } else {
            root = temp;
        }
        
        return temp;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Node rotateRight(Node node) {
        Node temp = node.left;
        temp.parent = node.parent;

        node.left = temp.right;
        if (node.left != nilNode) {
            node.left.parent = node;
        }

        temp.right = node;
        node.parent = temp;

        // temp took over node's place so now its parent should point to temp
        if (temp.parent != nilNode) {
            if (node == temp.parent.left) {
                temp.parent.left = temp;
            } else {
                temp.parent.right = temp;
            }
        } else {
            root = temp;
        }
        
        return temp;
    }

    
    /**
     * Similar to original transplant() method in BST but uses nilNode instead of null.
     */
    private Node rbTreeTransplant(Node nodeToReplace, Node newNode) {
        if (nodeToReplace.parent == nilNode) {
            this.root = newNode;
        } else if (nodeToReplace == nodeToReplace.parent.left) {
            nodeToReplace.parent.left = newNode;
        } else {
            nodeToReplace.parent.right = newNode;
        }
        newNode.parent = nodeToReplace.parent;
        return newNode;
    }
    
    /**
     * Restores Red-Black tree properties after delete if needed.
     */
    private void deleteRBFixup(RedBlackNode x) {
        while (x != root && isBlack(x)) {
            
            if (x == x.parent.left) {
                RedBlackNode w = (RedBlackNode)x.parent.right;
                if (isRed(w)) { // case 1 - sibling is red
                    w.color = ColorEnum.BLACK;
                    ((RedBlackNode)x.parent).color = ColorEnum.RED;
                    rotateLeft(x.parent);
                    w = (RedBlackNode)x.parent.right; // converted to case 2, 3 or 4
                }
                // case 2 sibling is black and both of its children are black
                if (isBlack(w.left) && isBlack(w.right)) {
                    w.color = ColorEnum.RED;
                    x = (RedBlackNode)x.parent;
                } else if (w != nilNode) {
                    if (isBlack(w.right)) { // case 3 sibling is black and its left child is red and right child is black
                        ((RedBlackNode)w.left).color = ColorEnum.BLACK;
                        w.color = ColorEnum.RED;
                        rotateRight(w);
                        w = (RedBlackNode)x.parent.right;
                    }
                    w.color = ((RedBlackNode)x.parent).color; // case 4 sibling is black and right child is red
                    ((RedBlackNode)x.parent).color = ColorEnum.BLACK;
                    ((RedBlackNode)w.right).color = ColorEnum.BLACK;
                    rotateLeft(x.parent);
                    x = (RedBlackNode)root;
                } else {
                    x.color = ColorEnum.BLACK;
                    x = (RedBlackNode)x.parent;
                }
            } else {
                RedBlackNode w = (RedBlackNode)x.parent.left;
                if (isRed(w)) { // case 1 - sibling is red
                    w.color = ColorEnum.BLACK;
                    ((RedBlackNode)x.parent).color = ColorEnum.RED;
                    rotateRight(x.parent);
                    w = (RedBlackNode)x.parent.left; // converted to case 2, 3 or 4
                }
                // case 2 sibling is black and both of its children are black
                if (isBlack(w.left) && isBlack(w.right)) {
                    w.color = ColorEnum.RED;
                    x = (RedBlackNode)x.parent;
                } else if (w != nilNode) {
                    if (isBlack(w.left)) { // case 3 sibling is black and its right child is red and left child is black
                        ((RedBlackNode)w.right).color = ColorEnum.BLACK;
                        w.color = ColorEnum.RED;
                        rotateLeft(w);
                        w = (RedBlackNode)x.parent.left;
                    }
                    w.color = ((RedBlackNode)x.parent).color; // case 4 sibling is black and left child is red
                    ((RedBlackNode)x.parent).color = ColorEnum.BLACK;
                    ((RedBlackNode)w.left).color = ColorEnum.BLACK;
                    rotateRight(x.parent);
                    x = (RedBlackNode)root;
                } else {
                    x.color = ColorEnum.BLACK;
                    x = (RedBlackNode)x.parent;
                }
            }
            
        }
    }
    
    private boolean isBlack(Node node) {
        return node != null ? ((RedBlackNode)node).color == ColorEnum.BLACK : false;
    }
    
    private boolean isRed(Node node) {
        return node != null ? ((RedBlackNode)node).color == ColorEnum.RED : false;
    }

    /**
     * Restores Red-Black tree properties after insert if needed. Insert can
     * break only 2 properties: root is red or if node is red then children must
     * be black.
     */
    private void insertRBFixup(RedBlackNode currentNode) {
        // current node is always RED, so if its parent is red it breaks
        // Red-Black property, otherwise no fixup needed and loop can terminate
        while (currentNode.parent != root && ((RedBlackNode) currentNode.parent).color == ColorEnum.RED) {
            RedBlackNode parent = (RedBlackNode) currentNode.parent;
            RedBlackNode grandParent = (RedBlackNode) parent.parent;
            if (parent == grandParent.left) {
                RedBlackNode uncle = (RedBlackNode) grandParent.right;
                // case1 - uncle and parent are both red
                // re color both of them to black
                if (((RedBlackNode) uncle).color == ColorEnum.RED) {
                    parent.color = ColorEnum.BLACK;
                    uncle.color = ColorEnum.BLACK;
                    grandParent.color = ColorEnum.RED;
                    // grandparent was recolored to red, so in next iteration we
                    // check if it does not break Red-Black property
                    currentNode = grandParent;
                } 
                // case 2/3 uncle is black - then we perform rotations
                else {
                    if (currentNode == parent.right) { // case 2, first rotate left
                        currentNode = parent;
                        rotateLeft(currentNode);
                        parent = (RedBlackNode) currentNode.parent;
                    }
                    // do not use parent
                    parent.color = ColorEnum.BLACK; // case 3
                    grandParent.color = ColorEnum.RED;
                    rotateRight(grandParent);
                }
            } else if (parent == grandParent.right) {
                RedBlackNode uncle = (RedBlackNode) grandParent.left;
                // case1 - uncle and parent are both red
                // re color both of them to black
                if (((RedBlackNode) uncle).color == ColorEnum.RED) {
                    parent.color = ColorEnum.BLACK;
                    uncle.color = ColorEnum.BLACK;
                    grandParent.color = ColorEnum.RED;
                    // grandparent was recolored to red, so in next iteration we
                    // check if it does not break Red-Black property
                    currentNode = grandParent;
                }
                // case 2/3 uncle is black - then we perform rotations
                else {
                    if (currentNode == parent.left) { // case 2, first rotate right
                        currentNode = parent;
                        rotateRight(currentNode);
                        parent = (RedBlackNode) currentNode.parent;
                    }
                    // do not use parent
                    parent.color = ColorEnum.BLACK; // case 3
                    grandParent.color = ColorEnum.RED;
                    rotateLeft(grandParent);
                }
            }

        }
        // ensure root is black in case it was colored red in fixup
        ((RedBlackNode) root).color = ColorEnum.BLACK;
    }

    protected static class RedBlackNode extends Node {
        public ColorEnum color;

        public RedBlackNode(Integer value, Node parent, Node left, Node right, ColorEnum color) {
            super(value, parent, left, right);
            this.color = color;
        }
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/ScapegoatTree.java
================================================
package org.intelligentjava.algos.trees;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.intelligentjava.algos.trees.utils.MathUtils;

/**
 * Scapegoat tree non recursive implementation.
 * Warning: not sure if my implementations is really correct, didn't have time to learn more about scapegoat trees.
 * 
 * @author Ignas Lelys
 * @created Jul 28, 2011
 * 
 */
public class ScapegoatTree extends AbstractSelfBalancingBinarySearchTree {

    /** Alpha parameter. */
    private double alpha = 0.57;
    
    private int maxSize = 0;
    
    /**
     * Constructor.
     */
    public ScapegoatTree() {
        super();
    }

    /**
     * Constructor.
     * 
     * @param alpha Alpha parameter.
     */
    public ScapegoatTree(double alpha) {
        super();
        this.alpha = alpha;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Node insert(int element) {
        Node inserted = super.insert(element);
        int height = getNodeHeight(inserted);
        if (height > getHAlpha()) {
            Node scapegoat = findScapegoatNode(inserted);
            Node scapegoatParent = scapegoat.parent;
            boolean scapegoatOnParentsLeft = scapegoatParent != null && scapegoatParent.left == scapegoat;
            Node rebuiltSubtree = rebuildTree(getSubtreeSize(scapegoat), scapegoat);
            rebuiltSubtree.parent = scapegoatParent;
            if (scapegoatParent != null) {
                if (scapegoatOnParentsLeft) {
                    scapegoatParent.left = rebuiltSubtree;
                } else {
                    scapegoatParent.right = rebuiltSubtree;
                }
            }
            if (scapegoat == root) {
                root = rebuiltSubtree;
            }
            maxSize = getSize();
        }
        return inserted;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    public Node delete(int element) {
        Node replaceNode = super.delete(element);
        if (getSize() <= alpha * maxSize) {
            root = rebuildTree(getSize(), root);
            maxSize = getSize();
        }
        return replaceNode;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new Node(value, parent, left, right);
    }
    
    /**
     * Finds scapegoat node which is used for rebalancing the tree.
     * 
     * @return Scapegoat node.
     */
    protected Node findScapegoatNode(Node node) {
        int size = 1;
        int height = 0;
        int totalSize = 0;
        while (node.parent != null) {
            height++;
            totalSize = 1 + size + getSubtreeSize(getSibling(node));
            if (height > Math.floor(MathUtils.logarithm(1 / alpha, totalSize))) {
                return node.parent;
            }
            node = node.parent;
            size = totalSize;
        }
        return null;
    }

    /**
     * Rebuilds unbalanced tree.
     * Found this implementation much clearer and easier to make it work: https://github.com/satchamo/Scapegoat-Tree/blob/master/scapegoat.py
     * Could't get implementations from pdfs to work.
     * 
     * @param size Size of subtree.
     * @param scapegoat Scapegoat is the root of subtree of {@link size} number of nodes.
     * 
     * @return Balanced subtree.
     */
    protected Node rebuildTree(int size, Node scapegoat) {
        List<Node> nodes = new ArrayList<Node>();
        
        // flatten tree without recursion
        Node currentNode = scapegoat;
        boolean done = false;
        Stack<Node> stack = new Stack<>();
        while (!done) {
            if (currentNode != null) {
                stack.push(currentNode);
                currentNode = currentNode.left;
            } else {
                if (!stack.isEmpty()) {
                    currentNode = stack.pop();
                    nodes.add(currentNode);
                    currentNode = currentNode.right;
                } else {
                    done = true;
                }
            }
        }
        
        // build tree from flattened list of nodes
        return buildTree(nodes, 0, size - 1);
    }
    
    /**
     * Build balanced tree from flattened tree.
     */
    private Node buildTree(List<Node> nodes, int start, int end) {
        int middle = (int)Math.ceil(((double)(start + end)) / 2.0);
        if (start > end) {
            return null;
        }

        // middle becomes root of subtree instead of scapegoat
        Node node = nodes.get(middle);
        
        // recursively get left and right nodes
        Node leftNode = buildTree(nodes, start, middle - 1);
        node.left = leftNode;
        if (leftNode != null) {
            leftNode.parent = node;
        }
        Node rightNode = buildTree(nodes, middle + 1, end);
        node.right = rightNode;
        if (rightNode != null) {
            rightNode.parent = node;
        }
        return node;
    }
    
    /**
     * @return Node's sibling.
     */
    // TODO move to AbstractBinaySearchTree and use in other trees where needed.
    private Node getSibling(Node node) {
        if (node.parent != null) {
            if (node.parent.left == node) {
                return node.parent.right;
            } else {
                return node.parent.left;
            }
        }
        return null;
    }
    
    /**
     * Calculate size of subtree.
     * 
     * @param node
     *            Subtree root node.
     * @return Number of elements in the subtree.
     */
    // TODO move to AbstractBinaySearchTree
    protected int getSubtreeSize(Node node) {
        if (node == null) {
            return 0;
        }
        if (node.isLeaf()) {
            return 1;
        } else {
            int sum = 1;
            sum += getSubtreeSize(node.left);
            sum += getSubtreeSize(node.right);
            return sum;
        }
    }
    
    // TODO move to AbstractBinaySearchTree
    protected int getNodeHeight(Node node) {
        if (node == null) {
            return -1;
        } else if (node.parent == null) {
            return 0;
        } else {
            return getNodeHeight(node.parent) + 1;
        }
    }

    private int getHAlpha() {
        return (int)Math.floor(MathUtils.logarithm(1 / alpha, (double)getSize()));
    }

}

================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/SplayTree.java
================================================
package org.intelligentjava.algos.trees;

/**
 * Splay tree implementation.
 * 
 * @author Ignas Lelys
 * @created Jul 19, 2011
 * 
 */
public class SplayTree extends AbstractSelfBalancingBinarySearchTree {

    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#search(int)
     */
    @Override
    public Node search(int element) {
        Node node = super.search(element);
        if (node != null) {
            splay(node);
        }
        return node;
    }
    
    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#insert(int)
     */
    @Override
    public Node insert(int element) {
        Node insertNode = super.insert(element);
        splay(insertNode);
        return insertNode;
    }

    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#delete(int)
     */
    @Override
    public Node delete(int element) {
        // search first, because need parent to splay, might be improved later if needed
        Node deleteNode = super.search(element); // do not use search with splaying
        Node successor = null;
        if (deleteNode != null) {
            Node parent = deleteNode.parent;
            successor = super.delete(deleteNode);
            if (parent != null) {
                splay(parent);
            }
        }
        return successor;
    }
    
    /**
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#createNode(int, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node, org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node)
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new Node(value, parent, left, right);
    }

    /**
     * Splay operation. Move node to the root through some tree transformations.
     * 
     * @param node
     *            Node to perform splay operation on.
     */
    protected void splay(Node node) {
        // move node up until its root
        while (node != root) {
            // Zig step
            Node parent = node.parent;
            if (parent.equals(root)) {
                if (node.equals(parent.left)) {
                    rotateRight(parent);
                } else if (node.equals(parent.right)) {
                    rotateLeft(parent);
                }
                break;
            } else {
                Node grandParent = parent.parent;
                boolean nodeAndParentLeftChildren = node.equals(parent.left) && parent.equals(grandParent.left);
                boolean nodeAndParentRightChildren = node.equals(parent.right) && parent.equals(grandParent.right);
                boolean nodeRightChildParentLeftChild = node.equals(parent.right) && parent.equals(grandParent.left);
                boolean nodeLeftChildParentRightChild = node.equals(parent.left) && parent.equals(grandParent.right);
                // Zig zig step to the right
                if (nodeAndParentLeftChildren) {
                    rotateRight(grandParent);
                    rotateRight(parent);
                }  
                // Zig zig step to the left
                else if (nodeAndParentRightChildren) {
                    rotateLeft(grandParent);
                    rotateLeft(parent);
                }
                // Zig zag steps
                else if (nodeRightChildParentLeftChild) {
                    rotateLeft(parent);
                    rotateRight(grandParent);
                }
                else if (nodeLeftChildParentRightChild) {
                    rotateRight(parent);
                    rotateLeft(grandParent);
                }
            }
        }
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/Treap.java
================================================
package org.intelligentjava.algos.trees;

import java.util.Random;

/**
 * Treap is randomized binary search tree. Easiest way to randomize would be to get all elements in array and then after
 * random permutation insert them all. However that would require to know all elements in advance. Treap solves this by
 * introducing additional variable to its node - priority which is generated randomly.
 * 
 * @author Ignas Lelys
 * @created Jul 25, 2011
 * 
 */
public class Treap extends AbstractSelfBalancingBinarySearchTree {

    private Random random = new Random(System.currentTimeMillis());

    /**
     * Insert same as normal binary search tree first, just TreapNode will have random number - priority. Then performs
     * rotations up until root if priority of child is larger than priority of parent.
     * 
     * @see org.intelligentjava.algos.trees.AbstractBinarySearchTree#insert(int)
     */
    @Override
    public Node insert(int element) {
        // insert as in normal BST
        TreapNode insertedNode = (TreapNode) super.insert(element);
        // then rebalance by randomized priority
        while (insertedNode != root) {
            TreapNode parent = (TreapNode) insertedNode.parent;
            if (parent.priority < insertedNode.priority) {
                if (insertedNode.equals(parent.left)) {
                    rotateRight(parent);
                } else {
                    rotateLeft(parent);
                }
            } else {
                break;
            }
        }
        return insertedNode;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Node delete(Node deleteNode) {
        if (deleteNode != null) {
            // rotate node down to leaf
            Node replaceNode = rotateDown((TreapNode)deleteNode);
            // then delete it normally
            super.delete(deleteNode);
            return replaceNode;
        }
        return null;
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new TreapNode(value, parent, left, right, random.nextInt(10000));
    }

    /**
     * Rotates a node downwards until it becomes a leaf. It must be deleted later to keep heap property intact.
     * 
     * @param node The node which is moved to leaf.
     * 
     * @return Node that replaces the one which is moved downwards to leaf.
     */
    private Node rotateDown(TreapNode node) {
        Node replaceNode = null;
        while (true) {
            if (node.left != null) {
                boolean leftNodePriorityLarger = node.right == null || ((TreapNode) node.left).priority >= ((TreapNode) node.right).priority;
                if (leftNodePriorityLarger) {
                    Node replace = rotateRight(node);
                    if (replaceNode == null) {
                        replaceNode = replace;
                    }
                } else {
                    Node replace = rotateLeft(node);
                    if (replaceNode == null) {
                        replaceNode = replace;
                    }
                }
            } else if (node.right != null) {
                Node replace = rotateLeft(node);
                if (replaceNode == null) {
                    replaceNode = replace;
                }
            } else {
                break;
            }
        }
        return replaceNode;
    }

    /**
     * Node for Treap. It has additional priority value which is set randomly. It is used for tree randomization.
     * 
     * @author Ignas Lelys
     * @created Jul 25, 2011
     */
    protected static class TreapNode extends Node {
        public int priority;

        public TreapNode(int value, Node parent, Node left, Node right, int priority) {
            super(value, parent, left, right);
            this.priority = priority;
        }
    }
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesDeleteBenchmark.java
================================================
package org.intelligentjava.algos.trees.benchmark;

import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.intelligentjava.algos.trees.AVLTree;
import org.intelligentjava.algos.trees.RedBlackTree;
import org.intelligentjava.algos.trees.ScapegoatTree;
import org.intelligentjava.algos.trees.SplayTree;
import org.intelligentjava.algos.trees.Treap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 2, time = 1)
@State(Scope.Thread)
public class TreesDeleteBenchmark {
    
    private static final int SIZE = 100000;
    
    private Integer[] randomInts = new Integer[SIZE];
  
    @Setup(Level.Trial)
    public void setup() {
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < SIZE; i++) {
            randomInts[i] = random.nextInt(SIZE);
        }
    }
    
    @Benchmark
    public Object timeJDKTreeSet() {
        TreeSet<Integer> treeSet = new TreeSet<>();
        for (int i = 0; i < SIZE; i++) {
            treeSet.add(randomInts[i]);
        }

        for (int i = 0; i < SIZE; i++) {
            treeSet.remove(randomInts[i]);
        }
        
        return treeSet.contains(randomInts[0]);
    }
    
    @Benchmark
    public Object timeDeleteRedBlackTree() {
        RedBlackTree rbTree = new RedBlackTree();
        for (int i = 0; i < SIZE; i++) {
            rbTree.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            rbTree.delete(randomInts[i]);
        }
        
        return rbTree.root;
    }

    @Benchmark
    public Object timeDeleteAVLTree() {
        AVLTree avlTree = new AVLTree();
        for (int i = 0; i < SIZE; i++) {
            avlTree.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            avlTree.delete(randomInts[i]);
        }
        
        return avlTree.root;
    }

    @Benchmark
    public Object timeDeleteSplayTree() {
        SplayTree splayTree = new SplayTree();
        for (int i = 0; i < SIZE; i++) {
            splayTree.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            splayTree.delete(randomInts[i]);
        }
        
        return splayTree.root;
    }

    @Benchmark
    public Object timeDeleteTreap() {
        Treap treap = new Treap();
        for (int i = 0; i < SIZE; i++) {
            treap.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            treap.delete(randomInts[i]);
        }
        
        return treap.root;
    }

    @Benchmark
    public Object timeDeleteScapegoat0_6Tree() {
        ScapegoatTree scapegoatTree0_6 = new ScapegoatTree(0.6);
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_6.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_6.delete(randomInts[i]);
        }
        
        return scapegoatTree0_6.root;
    }

    @Benchmark
    public Object timeDeleteScapegoat0_75Tree() {
        ScapegoatTree scapegoatTree0_75 = new ScapegoatTree(0.75);
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_75.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_75.delete(randomInts[i]);
        }
        
        return scapegoatTree0_75.root;
    }
    
    @Benchmark
    public Object timeDeleteScapegoat0_9Tree() {
        ScapegoatTree scapegoatTree0_9 = new ScapegoatTree(0.9);
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_9.insert(randomInts[i]);
        }
        
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_9.delete(randomInts[i]);
        }
        
        return scapegoatTree0_9.root;
    }
    
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(".*" + TreesDeleteBenchmark.class.getSimpleName() + ".*").forks(1)
                .build();

        new Runner(opt).run();
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertRandomBenchmark.java
================================================
package org.intelligentjava.algos.trees.benchmark;

import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.intelligentjava.algos.trees.AVLTree;
import org.intelligentjava.algos.trees.RedBlackTree;
import org.intelligentjava.algos.trees.ScapegoatTree;
import org.intelligentjava.algos.trees.SplayTree;
import org.intelligentjava.algos.trees.Treap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 2, time = 1)
@State(Scope.Thread)
public class TreesInsertRandomBenchmark {
    
    private static final int SIZE = 100000;

    private Integer[] randomInts = new Integer[SIZE];
    
    @Setup(Level.Trial)
    public void setup() {
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < SIZE; i++) {
            randomInts[i] = random.nextInt(SIZE);
        }
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Benchmark
    public Object timeJDKTreeSet() {
        TreeSet tree = new TreeSet();
        for (int i = 0; i < SIZE; i++) {
            tree.add(randomInts[i]);
        }
        return tree.contains(Integer.MAX_VALUE);
    }

    @Benchmark
    public Object timeRedBlackTree() {
        RedBlackTree tree = new RedBlackTree();
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeAVLTree() {
        AVLTree tree = new AVLTree();
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeSplayTree() {
        SplayTree tree = new SplayTree();
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeTreap() {
        Treap tree = new Treap();
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeScapegoat0_6Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.6);
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }
    
    @Benchmark
    public Object timeScapegoat0_75Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.75);
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }
    
    @Benchmark
    public Object timeScapegoat0_9Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.9);
        for (int i = 0; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }
        return tree.root;
    }
    
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(".*" + TreesInsertRandomBenchmark.class.getSimpleName() + ".*").forks(1)
                .build();

        new Runner(opt).run();
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertSortedBenchmark.java
================================================
package org.intelligentjava.algos.trees.benchmark;

import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.intelligentjava.algos.trees.AVLTree;
import org.intelligentjava.algos.trees.RedBlackTree;
import org.intelligentjava.algos.trees.ScapegoatTree;
import org.intelligentjava.algos.trees.SplayTree;
import org.intelligentjava.algos.trees.Treap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 2, time = 1)
@State(Scope.Thread)
public class TreesInsertSortedBenchmark {
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Benchmark
    public Object timeJDKTreeSet() {
        TreeSet tree = new TreeSet();
        for (int i = 0; i < 100000; i++) {
            tree.add(i);
        }
        return tree.contains(Integer.MAX_VALUE);
    }

    @Benchmark
    public Object timeRedBlackTree() {
        RedBlackTree tree = new RedBlackTree();
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeAVLTree() {
        AVLTree tree = new AVLTree();
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeSplayTree() {
        SplayTree tree = new SplayTree();
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeTreap() {
        Treap tree = new Treap();
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }

    @Benchmark
    public Object timeScapegoat0_6Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.6);
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }
    
    @Benchmark
    public Object timeScapegoat0_75Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.75);
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }
    
    @Benchmark
    public Object timeScapegoat0_9Tree() {
        ScapegoatTree tree = new ScapegoatTree(0.9);
        for (int i = 0; i < 100000; i++) {
            tree.insert(i);
        }
        return tree.root;
    }
    
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(".*" + TreesInsertSortedBenchmark.class.getSimpleName() + ".*").forks(1)
                .build();

        new Runner(opt).run();
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchBenchmark.java
================================================
package org.intelligentjava.algos.trees.benchmark;

import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.intelligentjava.algos.trees.AVLTree;
import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.intelligentjava.algos.trees.RedBlackTree;
import org.intelligentjava.algos.trees.ScapegoatTree;
import org.intelligentjava.algos.trees.SplayTree;
import org.intelligentjava.algos.trees.Treap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@SuppressWarnings("unchecked")
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 2, time = 1)
@State(Scope.Thread)
public class TreesSearchBenchmark {
    
    private static final int SIZE = 100000;
    @SuppressWarnings("rawtypes")
    private TreeSet treeSet = new TreeSet();
    private RedBlackTree rbTree = new RedBlackTree();
    private AVLTree avlTree = new AVLTree();
    private SplayTree splayTree = new SplayTree();
    private Treap treap = new Treap();
    private ScapegoatTree scapegoatTree0_6 = new ScapegoatTree(0.6);
    private ScapegoatTree scapegoatTree0_75 = new ScapegoatTree(0.75);
    private ScapegoatTree scapegoatTree0_9 = new ScapegoatTree(0.9);
    private Integer[] randomInts = new Integer[SIZE];
    
    @Setup(Level.Trial)
    public void setup() {
        Random random = new Random(System.currentTimeMillis());
        for (Integer i = 0; i < SIZE; i++) {
            randomInts[i] = random.nextInt(SIZE);
        }
        for (int i = 0; i < SIZE; i++) {
            rbTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            treeSet.add(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            avlTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            splayTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            treap.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_6.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_75.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_9.insert(randomInts[i]);
        }
    }
    
    
    @Benchmark
    public boolean timeJDKTreeSet() {
        boolean[] booleans = new boolean[SIZE];
        for (int i = 0; i < SIZE; i++) {
            booleans[i] = treeSet.contains(randomInts[i]);
        }
        return booleans[0];
    }
    
    @Benchmark
    public Node timeSearchRedBlackTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = rbTree.search(randomInts[i]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchAVLTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = avlTree.search(randomInts[i]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchSplayTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = splayTree.search(randomInts[i]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchTreap() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = treap.search(randomInts[i]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchScapegoat0_6Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_6.search(randomInts[i]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchScapegoat0_75Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_75.search(randomInts[i]);
        }
        return nodes[0];
    }
    
    @Benchmark
    public Node timeSearchScapegoat0_9Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_9.search(randomInts[i]);
        }
        return nodes[0];
    }
    
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(".*" + TreesDeleteBenchmark.class.getSimpleName() + ".*").forks(1)
                .build();

        new Runner(opt).run();
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchSameElementsBenchmark.java
================================================
package org.intelligentjava.algos.trees.benchmark;

import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;

import org.intelligentjava.algos.trees.AVLTree;
import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.intelligentjava.algos.trees.RedBlackTree;
import org.intelligentjava.algos.trees.ScapegoatTree;
import org.intelligentjava.algos.trees.SplayTree;
import org.intelligentjava.algos.trees.Treap;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@SuppressWarnings("unchecked")
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1, time = 1)
@Measurement(iterations = 3, time = 1)
@State(Scope.Thread)
public class TreesSearchSameElementsBenchmark {
    
    private static final int SIZE = 100000;
    @SuppressWarnings("rawtypes")
    private TreeSet treeSet = new TreeSet();
    private RedBlackTree rbTree = new RedBlackTree();
    private AVLTree avlTree = new AVLTree();
    private SplayTree splayTree = new SplayTree();
    private Treap treap = new Treap();
    private ScapegoatTree scapegoatTree0_6 = new ScapegoatTree(0.6);
    private ScapegoatTree scapegoatTree0_75 = new ScapegoatTree(0.75);
    private ScapegoatTree scapegoatTree0_9 = new ScapegoatTree(0.9);
    private Integer[] randomInts = new Integer[SIZE];
    
    @Setup(Level.Trial)
    public void setup() {
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < SIZE; i++) {
            randomInts[i] = random.nextInt(SIZE);
        }
        for (int i = 0; i < SIZE; i++) {
            rbTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            treeSet.add(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            avlTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            splayTree.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            treap.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_6.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_75.insert(randomInts[i]);
        }
        for (int i = 0; i < SIZE; i++) {
            scapegoatTree0_9.insert(randomInts[i]);
        }
    }
    
    @Benchmark
    public boolean timeJDKTreeSet() {
        boolean[] booleans = new boolean[SIZE];
        for (int i = 0; i < SIZE; i++) {
            booleans[i] = treeSet.contains(randomInts[i % 100]);
        }
        return booleans[0];
    }
    
    @Benchmark
    public Node timeSearchRedBlackTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = rbTree.search(randomInts[i % 100]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchAVLTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = avlTree.search(randomInts[i % 100]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchSplayTree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = splayTree.search(randomInts[i  % 100]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchTreap() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = treap.search(randomInts[i  % 100]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchScapegoat0_6Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_6.search(randomInts[i  % 100]);
        }
        return nodes[0];
    }

    @Benchmark
    public Node timeSearchScapegoat0_75Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_75.search(randomInts[i  % 100]);
        }
        return nodes[0];
    }
    
    @Benchmark
    public Node timeSearchScapegoat0_9Tree() {
        Node[] nodes = new Node[SIZE];
        for (int i = 0; i < SIZE; i++) {
            nodes[i] = scapegoatTree0_9.search(randomInts[i % 100]);
        }
        return nodes[0];
    }
    
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(".*" + TreesDeleteBenchmark.class.getSimpleName() + ".*").forks(1)
                .build();

        new Runner(opt).run();
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/exceptions/QueueOverflowException.java
================================================
package org.intelligentjava.algos.trees.exceptions;

/**
 * Exception when queue overflow.
 * 
 * @author Ignas Lelys
 * @created May 4, 2011
 *
 */
public class QueueOverflowException extends Exception {

    private static final long serialVersionUID = 1L;

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/main/Main.java
================================================
package org.intelligentjava.algos.trees.main;

import java.util.Random;

import org.intelligentjava.algos.trees.RedBlackTree;

public class Main {

    private static final int SIZE = 100;

    public static void main(String[] args) {
        Random random = new Random(System.currentTimeMillis());
        Integer[] randomInts = new Integer[SIZE];
        for (int i = 0; i < SIZE; i++) {
            randomInts[i] = random.nextInt(SIZE);
        }

        long currentTimeMillis = System.currentTimeMillis();
        RedBlackTree tree = new RedBlackTree();
        for (int i = 1; i < SIZE; i++) {
            tree.insert(randomInts[i]);
        }

        for (int i = 1; i < SIZE / 2; i++) {
            tree.delete(randomInts[i]);
        }
        
        tree.printTree();

        System.out.println(System.currentTimeMillis() - currentTimeMillis + " ms");
    }

}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/ArrayUtils.java
================================================
package org.intelligentjava.algos.trees.utils;

/**
 * Helper class which helps to work with arrays.
 * 
 * @author Ignas Lelys
 * @created Apr 18, 2011
 * 
 */
public class ArrayUtils {

    /**
     * Swaps elements in array.
     * 
     * @param data
     *            Array of elements.
     * @param elementIndex1
     *            Index of element which value will be moved to elementIndex2.
     * @param elementIndex2
     *            Index of element which value will be moved to elementIndex1.
     */
    public static void swap(int[] data, int elementIndex1, int elementIndex2) {
        int tmp = data[elementIndex1];
        data[elementIndex1] = data[elementIndex2];
        data[elementIndex2] = tmp;
    }

    /**
     * Select nth smallest element in array. It could be easily solved by
     * sorting array and select nth element, but this algorithm is more
     * efficient. Expected running time is O(n). However worst case scenario
     * could be O(n^2).
     * 
     * @param data Data array.
     * @param n N parameter.
     * @return Value of nth smallest element.
     */
    public static int selectNthSmallestElement(int[] data, int n) {
        return selectNthSmallestElement(data, 0, data.length - 1, n);
    }

    /**
     * Select nth smallest element in array from sublist.
     * 
     * @param @param data Data array.
     * @param sublistStartIndex Sublist start index.
     * @param sublistEndIndex Sublist end index.
     * @param n N parameter.
     * @return Value of nth smallest element in sublist.
     */
    public static int selectNthSmallestElement(int[] data, int sublistStartIndex, int sublistEndIndex, int n) {
        if (sublistStartIndex == sublistEndIndex) {
            return data[sublistStartIndex];
        }
        int pivotIndex = partition(data, sublistStartIndex, sublistEndIndex);
        int k = sublistStartIndex - pivotIndex + 1;
        if (n == k) {
            return data[pivotIndex];
        } else if (n < k) {
            return selectNthSmallestElement(data, sublistStartIndex, pivotIndex - 1, n);
        } else {
            return selectNthSmallestElement(data, pivotIndex, sublistEndIndex, n - k);
        }
        
    }

    /**
     * Partition algorithm.
     * 
     * @param @param data Data array.
     * @param sublistStartIndex Sublist start index.
     * @param sublistEndIndex Sublist end index.
     * @return Pivot index.
     */
    private static int partition(int[] data, int sublistStartIndex, int sublistEndIndex) {
        int pivotElement = data[sublistEndIndex];
        int pivotIndex = sublistStartIndex - 1;
        for (int i = sublistStartIndex; i < sublistEndIndex; i++) {
            if (data[i] <= pivotElement) {
                pivotIndex++;
                ArrayUtils.swap(data, pivotIndex, i);
            }
        }
        ArrayUtils.swap(data, pivotIndex + 1, sublistEndIndex);
        return pivotIndex + 1;
    }
    
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/HeapUtils.java
================================================
package org.intelligentjava.algos.trees.utils;

/**
 * Utils for working with heap data structure. Heap is a tree like data
 * structure, which has root element always bigger than its children.
 * Example of a heap:
 *              100
 *               /\
 *             90  23
 *             /\  /
 *           45  1 15
 * Heap is used in heap sort and priority queues implementations.
 */
public class HeapUtils {
    
    /**
     * @param data
     * @param index
     */
    public static void buildMaxHeap(int[] data) {
        for (int i = data.length/2; i >= 0; i--) {
            maxHeapify(data, i);
        }
    }
    
    /**
     * This method takes array and index of root element (of heap subtree). It
     * assumes that this element might not
     * 
     * @param data
     * @param index
     */
    public static void maxHeapify(int[] data, int index) {
        maxHeapify(data, index, data.length);
    }
    
    /**
     * @param data
     * @param index
     * @param heapSize
     */
    public static void maxHeapify(int[] data, int index, int heapSize) {
        int leftLeaf = getLeftLeaf(index);
        int rightLeaf = getRightLeaf(index);
        int largest = index;
        if (leftLeaf < heapSize && data[leftLeaf] > data[largest]) {
            largest = leftLeaf;
        }
        if (rightLeaf < heapSize && data[rightLeaf] > data[largest]) {
            largest = rightLeaf;
        }
        if (largest != index) {
            ArrayUtils.swap(data, index, largest);
            HeapUtils.maxHeapify(data, largest, heapSize);
        }
    }

    public static int getParent(int leafIndex) {
        return leafIndex / 2;
    }
    
    /**
     * Calculates index of left child node.
     * 
     * @param parentIndex
     *            Array index that represents parent node.
     * @return Left child node index in array.
     */
    private static int getLeftLeaf(int parentIndex) {
        return 2 * parentIndex+1;
    }

    /**
     * Calculates index of right child node.
     * 
     * @param parentIndex
     *            Array index that represents parent node.
     * @return Right child node index in array.
     */
    private static int getRightLeaf(int parentIndex) {
        return 2 * parentIndex + 2;
    }
}


================================================
FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/MathUtils.java
================================================
package org.intelligentjava.algos.trees.utils;

/**
 * Some syntactic sugar for math operations.
 * 
 * @author Ignas Lelys
 * @created May 3, 2011
 *
 */
public class MathUtils {
    
    /**
     * Extracts digit from integer number.
     * 
     * @param number Number from which digit is extracted.
     * @param digitIndex index of digit to get. 0 - last one.
     * 
     * @return Required digit.
     */
    public static int getDigitFromNumber(int number, int digitIndex) {
        // TODO error check and efficiency (maybe put powers of 10 to array)
        return number / (int)Math.pow(10, digitIndex) % 10;
    }
    
    /**
     * Returns bigger integer.
     * 
     * @param first First number.
     * @param second Second number.
     * @return Bigger number.
     */
    public static int getMax(int first, int second) {
        return first > second ? first : second;
    }
    
    /**
     * Calculates logarithm.
     */
    public static double logarithm(double base, double a) {
        return Math.log(a) / Math.log(base);
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/LinkedListTest.java
================================================
package org.intelligentjava.algos.simplestructures;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created May 5, 2011
 *
 */
public class LinkedListTest {
    
    @Test
    public void testInsertDelete() {
        LinkedList list = new LinkedList();
        list.insert(1);
        list.insert(2);
        list.insert(3);
        list.insert(4);
        list.insert(5);
        Assert.assertEquals(list.get(0), 5);
        Assert.assertEquals(list.get(1), 4);
        Assert.assertEquals(list.get(2), 3);
        Assert.assertEquals(list.get(3), 2);
        Assert.assertEquals(list.get(4), 1);
        list.delete(5);
        Assert.assertEquals(list.get(0), 4);
        Assert.assertEquals(list.get(1), 3);
        Assert.assertEquals(list.get(2), 2);
        Assert.assertEquals(list.get(3), 1);
        list.delete(1);
        Assert.assertEquals(list.get(0), 4);
        Assert.assertEquals(list.get(1), 3);
        Assert.assertEquals(list.get(2), 2);
        list.delete(3);
        Assert.assertEquals(list.get(0), 4);
        Assert.assertEquals(list.get(1), 2);
        
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/PriorityQueueTest.java
================================================
package org.intelligentjava.algos.simplestructures;

/**
 * @author Ignas Lelys
 * @created May 4, 2011
 *
 */
public class PriorityQueueTest {

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/QueueTest.java
================================================
package org.intelligentjava.algos.simplestructures;

import org.intelligentjava.algos.trees.exceptions.QueueOverflowException;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created May 4, 2011
 *
 */
public class QueueTest {
    
    @Test
    public void testEnqueueDequeue() throws QueueOverflowException {
        Queue queue = new Queue();
        queue.enqueue(1);
        queue.enqueue(2);
        queue.enqueue(3);
        Assert.assertEquals(queue.dequeue(), 1);
        Assert.assertEquals(queue.dequeue(), 2);
        Assert.assertEquals(queue.dequeue(), 3);
    }

    @Test
    public void testIsEmpty() throws QueueOverflowException {
        Queue queue = new Queue();
        Assert.assertTrue(queue.isEmpty());
        queue.enqueue(1);
        Assert.assertFalse(queue.isEmpty());
    }
    
    @Test
    public void testIsFull() throws QueueOverflowException {
        Queue queue = new Queue();
        for (int i = 0; i < 8; i++) {
            queue.enqueue(i);
        }
        Assert.assertFalse(queue.isFull());
        queue.enqueue(9);
        Assert.assertTrue(queue.isFull());
        queue.dequeue();
        Assert.assertFalse(queue.isFull());
        queue.enqueue(10);
        Assert.assertTrue(queue.isFull());
    }
    
//    @Test(expectedExceptions = { QueueOverflowException.class })
//    public void testQueueOverflow() throws QueueOverflowException {
//        Queue queue = new Queue();
//        for (int i = 0; i < 11; i++) {
//            queue.enqueue(i);
//        }
//    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/StackTest.java
================================================
package org.intelligentjava.algos.simplestructures;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created May 4, 2011
 * 
 */
public class StackTest {

    @Test
    public void testPushPop() {
        Stack stack = new Stack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        Assert.assertEquals(stack.pop(), 3);
        Assert.assertEquals(stack.pop(), 2);
        Assert.assertEquals(stack.pop(), 1);
    }

    @Test
    public void testIsEmpty() {
        Stack stack = new Stack();
        Assert.assertTrue(stack.isEmpty());
        stack.push(1);
        Assert.assertFalse(stack.isEmpty());
    }

    /**
     * Inserts more than 10 elements to stack. (Tests if inner array grows
     * correctly because starting size for it is 10 elements).
     */
    @Test
    public void testMoreThan10() {
        Stack stack = new Stack();
        for (int i = 0; i < 100; i++) {
            stack.push(i);
        }
        for (int i = 99; i >= 0; i--) {
            Assert.assertEquals(stack.pop(), i);
        }
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/AVLTreeTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AVLTree.AVLNode;
import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.junit.Assert;
import org.junit.Test;

/**
 * Tests for AVL tree.
 * 
 * @author Ignas Lelys
 * @created Jun 29, 2011
 *
 */
public class AVLTreeTest extends BaseBSTTest {
    
    @Test
    public void testDelete() {
        AVLTree tree = new AVLTree();
        tree.insert(20);
        tree.insert(15);
        tree.insert(25);
        tree.insert(23);
        Assert.assertEquals(tree.size, 4);
        tree.delete(15); // root is now unbalanced rotation performed
        Assert.assertEquals(tree.size, 3);
        Assert.assertEquals(tree.root.value, (Integer)23); // new root
        Assert.assertEquals(((AVLNode)tree.root).height, 1); // new root
        Assert.assertEquals(tree.root.left.value, (Integer)20);
        Assert.assertEquals(tree.root.right.value, (Integer)25);
        
        testTreeBSTProperties(tree.root);
    }
    
    @Test
    public void testInsert() {
        AVLTree tree = new AVLTree();
        tree.insert(20);
        tree.insert(15);
        tree.insert(25);
        tree.insert(22);
        tree.insert(21);
        Assert.assertEquals(tree.size, 5);
        Assert.assertEquals((int) tree.root.value, 20);
        Assert.assertEquals((int) tree.root.left.value, 15);
        AVLNode rightSubtree = (AVLNode) tree.root.right;
        // rotation performed and height+balance updated
        Assert.assertEquals((int) rightSubtree.value, 22);
        Assert.assertEquals((int) rightSubtree.height, 1);
        Assert.assertEquals((int) rightSubtree.right.value, 25);
        Assert.assertEquals(((AVLNode) rightSubtree.right).height, 0);
        Assert.assertEquals((int) rightSubtree.left.value, 21);
        Assert.assertEquals(((AVLNode) rightSubtree.left).height, 0);
        
        testTreeBSTProperties(tree.root);
    }

    @Test
    public void testRotateLeft() {
        Node root = new AVLNode(4, null, null, null);
        Node rightChild = new AVLNode(6, root, null, null);
        root.right = rightChild;
        Node leftGrandChild = new AVLNode(5, rightChild, null, null);
        Node rightGrandChild = new AVLNode(7, rightChild, null, null);
        rightChild.left = leftGrandChild;
        rightChild.right = rightGrandChild;

        AVLTree tree = new AVLTree();
        Node rotated = tree.rotateLeft(root);

        Assert.assertEquals((int) rotated.value, 6);
        Assert.assertEquals((int) rotated.left.value, 4);
        Assert.assertEquals((int) rotated.right.value, 7);
        Assert.assertEquals((int) rotated.left.right.value, 5);

        Assert.assertNull(rotated.parent);
        Assert.assertEquals(rotated.left.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.parent.value, rotated.value);
        Assert.assertEquals(rotated.left.right.parent.value, rotated.left.value);
    }

    @Test
    public void testRotateRight() {
        Node root = new AVLNode(8, null, null, null);
        Node leftChild = new AVLNode(6, root, null, null);
        root.left = leftChild;
        Node leftGrandChild = new AVLNode(5, leftChild, null, null);
        Node rightGrandChild = new AVLNode(7, leftChild, null, null);
        leftChild.left = leftGrandChild;
        leftChild.right = rightGrandChild;

        AVLTree tree = new AVLTree();
        Node rotated = tree.rotateRight(root);

        Assert.assertEquals((int) rotated.value, 6);
        Assert.assertEquals((int) rotated.left.value, 5);
        Assert.assertEquals((int) rotated.right.value, 8);
        Assert.assertEquals((int) rotated.right.left.value, 7);

        Assert.assertNull(rotated.parent);
        Assert.assertEquals(rotated.left.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.left.parent.value, rotated.right.value);
    }

    @Test
    public void testDoubleRotateRightLeft() {
        Node root = new AVLNode(5, null, null, null);
        Node rightChild = new AVLNode(8, root, null, null);
        root.right = rightChild;
        Node leftGrandChild = new AVLNode(7, rightChild, null, null);
        Node rightGrandChild = new AVLNode(10, rightChild, null, null);
        rightChild.left = leftGrandChild;
        rightChild.right = rightGrandChild;

        AVLTree tree = new AVLTree();
        Node rotated = tree.doubleRotateRightLeft(root);

        Assert.assertEquals((int) rotated.value, 7);
        Assert.assertEquals((int) rotated.left.value, 5);
        Assert.assertEquals((int) rotated.right.value, 8);
        Assert.assertEquals((int) rotated.right.right.value, 10);

        Assert.assertNull(rotated.parent);
        Assert.assertEquals(rotated.left.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.right.parent.value, rotated.right.value);
    }

    @Test
    public void testDoubleRotateLeftRight() {
        Node root = new AVLNode(5, null, null, null);
        Node leftChild = new AVLNode(3, root, null, null);
        root.left = leftChild;
        Node leftGrandChild = new AVLNode(1, leftChild, null, null);
        Node rightGrandChild = new AVLNode(4, leftChild, null, null);
        leftChild.left = leftGrandChild;
        leftChild.right = rightGrandChild;

        AVLTree tree = new AVLTree();
        Node rotated = tree.doubleRotateLeftRight(root);

        Assert.assertEquals((int) rotated.value, 4);
        Assert.assertEquals((int) rotated.left.value, 3);
        Assert.assertEquals((int) rotated.right.value, 5);
        Assert.assertEquals((int) rotated.left.left.value, 1);

        Assert.assertNull(rotated.parent);
        Assert.assertEquals(rotated.left.parent.value, rotated.value);
        Assert.assertEquals(rotated.right.parent.value, rotated.value);
        Assert.assertEquals(rotated.left.left.parent.value, rotated.left.value);
    }
}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/BaseBSTTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.junit.Assert;

/**
 * Superclass that contains some basic BST tests.
 * 
 * @author Ignas
 *
 */
public class BaseBSTTest {
    
    protected void testTreeBSTProperties(Node entry) {
        if (entry != null) {
            // test heap properties and BST properties
            if (entry.left != null) {
                Assert.assertTrue(entry.value >= entry.left.value);
            }
            if (entry.right != null) {
                Assert.assertTrue(entry.value <= entry.right.value);
            }
            testTreeBSTProperties(entry.left);
            testTreeBSTProperties(entry.right);
        }
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/BinarySearchTreeTest.java
================================================
package org.intelligentjava.algos.trees;

import org.junit.Assert;
import org.junit.Test;

/**
 * Tests for simple unbalanced binary search tree.
 * 
 * @author Ignas Lelys
 * @created May 6, 2011
 *
 */
public class BinarySearchTreeTest extends BaseBSTTest {
    
    @Test
    public void testInsertDelete() {
        BinarySearchTree tree = new BinarySearchTree();
        tree.insert(10);
        tree.insert(16);
        tree.insert(1);
        tree.insert(8);
        Assert.assertTrue(tree.contains(10));
        Assert.assertTrue(tree.contains(16));
        Assert.assertTrue(tree.contains(1));
        Assert.assertFalse(tree.contains(9));
        tree.delete(16);
        tree.delete(1);
        Assert.assertFalse(tree.contains(16));
        Assert.assertFalse(tree.contains(1));
        
        testTreeBSTProperties(tree.root);
    }
    
    @Test
    public void testSize() {
        BinarySearchTree tree = new BinarySearchTree();
        tree.insert(10);
        tree.insert(16);
        tree.insert(1);
        Assert.assertEquals(tree.getSize(), 3);
        tree.delete(16);
        Assert.assertEquals(tree.getSize(), 2);
        tree.delete(16);
        Assert.assertEquals(tree.getSize(), 2);
    }

    @Test
    public void testMinimumMaximum() {
        BinarySearchTree tree = new BinarySearchTree();
        tree.insert(10);
        tree.insert(16);
        tree.insert(1);
        tree.insert(8);
        Assert.assertEquals(tree.getMinimum(), 1);
        Assert.assertEquals(tree.getMaximum(), 16);
    }
    
    @Test
    public void testGetSuccessor() {
        BinarySearchTree tree = new BinarySearchTree();
        tree.insert(15);
        tree.insert(6);
        tree.insert(18);
        tree.insert(17);
        tree.insert(20);
        tree.insert(3);
        tree.insert(7);
        tree.insert(2);
        tree.insert(4);
        tree.insert(13);
        tree.insert(9);
        Assert.assertEquals(tree.getSuccessor(15), 17);
        Assert.assertEquals(tree.getSuccessor(13), 15);
    }
}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/RedBlackTreeTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.intelligentjava.algos.trees.RedBlackTree.ColorEnum;
import org.intelligentjava.algos.trees.RedBlackTree.RedBlackNode;
import org.junit.Assert;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

/**
 * Tests for Red-Black tree.
 * 
 * @author Ignas Lelys
 * @created Jul 18, 2011
 *
 */
public class RedBlackTreeTest {
    @Test
    public void testInsertionFixupColoring() throws Exception {
        RedBlackTree tree = new RedBlackTree();
        Node node8 = tree.insert(8);
        Node node3 = tree.insert(3);
        Node node4 = tree.insert(4);
        assertThat(((RedBlackNode)node3).color, equalTo(ColorEnum.RED));
        assertThat(((RedBlackNode)node4).color, equalTo(ColorEnum.BLACK));
        assertThat(((RedBlackNode)node8).color, equalTo(ColorEnum.RED));
    }

    @Test
    public void testInsert() {
        RedBlackTree tree = new RedBlackTree();
        tree.insert(20);
        tree.insert(15);
        tree.insert(25);
        tree.insert(10); // re color 15 and 25 to black on this insert
        Assert.assertEquals(((RedBlackNode)tree.root).color, ColorEnum.BLACK);
        Assert.assertEquals(((RedBlackNode)tree.search(15)).color, ColorEnum.BLACK);
        Assert.assertEquals(((RedBlackNode)tree.search(25)).color, ColorEnum.BLACK);
        tree.insert(17);
        tree.insert(8);
        Assert.assertEquals(((RedBlackNode)tree.search(15)).color, ColorEnum.RED);
        Assert.assertEquals(((RedBlackNode)tree.search(10)).color, ColorEnum.BLACK);
        Assert.assertEquals(((RedBlackNode)tree.search(17)).color, ColorEnum.BLACK);
        Assert.assertEquals(((RedBlackNode)tree.search(8)).color, ColorEnum.RED);
        tree.insert(9); // case 2/3 - rotation right, then left
        Assert.assertEquals(((RedBlackNode)tree.search(10)).color, ColorEnum.RED);
        Assert.assertEquals(((RedBlackNode)tree.search(8)).color, ColorEnum.RED);
        Assert.assertEquals(((RedBlackNode)tree.search(9)).left.value, (Integer)8);
        
        // TODO test other red black tree properties too
        testTreeBSTProperties(tree.root);
    }
    
    @Test
    public void testSimpleDelete() {
        RedBlackTree tree = new RedBlackTree();
        tree.insert(20);
        tree.insert(15);
        tree.insert(25);
        tree.insert(23);
        Assert.assertEquals(((RedBlackNode)tree.root).color, ColorEnum.BLACK);
        Assert.assertEquals(tree.size, 4);
        tree.delete(15);
        Assert.assertEquals(tree.size, 3);
        Assert.assertEquals(tree.root.value, (Integer)23); // new root
        
        testTreeBSTProperties(tree.root);
    }
    
    @Test
    public void testDelete() {
        RedBlackTree tree = new RedBlackTree();
        tree.insert(20);
        tree.insert(15);
        tree.insert(25);
        tree.insert(23);
        tree.insert(27);
        Assert.assertEquals(((RedBlackNode)tree.root).color, ColorEnum.BLACK);
        Assert.assertEquals(tree.size, 5);
        Assert.assertEquals(tree.root.right.value, (Integer)25);
        Assert.assertEquals(tree.root.right.left.value, (Integer)23);
        Assert.assertEquals(((RedBlackNode)tree.root.right.left).color, ColorEnum.RED);
        tree.delete(25);
        Assert.assertEquals(tree.size, 4);
        Assert.assertEquals(tree.root.value, (Integer)20);
        Assert.assertEquals(tree.root.right.value, (Integer)27);
        Assert.assertEquals(((RedBlackNode)tree.root.right).color, ColorEnum.BLACK);
        Assert.assertEquals(tree.root.right.right.value, null);
        Assert.assertEquals(tree.root.right.left.value, (Integer)23);
        Assert.assertEquals(((RedBlackNode)tree.root.right.left).color, ColorEnum.RED);
        
        testTreeBSTProperties(tree.root);
    }

    
    /**
     * Test BST properties method for RedBlack tree. Not using the one from {@link BaseBSTTest} because RedBlack tree implementation uses nilNode instead of nulls.
     */
    private void testTreeBSTProperties(Node entry) {
        if (entry != RedBlackTree.nilNode) {
            // test heap properties and BST properties
            if (entry.left != RedBlackTree.nilNode) {
                Assert.assertTrue(entry.value >= entry.left.value);
            }
            if (entry.right != RedBlackTree.nilNode) {
                Assert.assertTrue(entry.value <= entry.right.value);
            }
            testTreeBSTProperties(entry.left);
            testTreeBSTProperties(entry.right);
        }
    }
}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/ScapegoatTreeTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.junit.Assert;
import org.junit.Test;

/**
 * Scapegoat tree implementation tests.
 * 
 * @author Ignas Lelys
 * @created Jul 28, 2011
 *
 */
public class ScapegoatTreeTest extends BaseBSTTest {
    
    
    @Test
    public void testInsertSorted() {
        ScapegoatTree tree = new ScapegoatTree();
        tree.insert(1);
        tree.insert(2);
        tree.insert(3);
        tree.insert(4);
        tree.insert(5);
        tree.insert(6);
        tree.insert(7);
        tree.insert(8);
        tree.insert(9);
        tree.insert(10);
        tree.insert(11);
        tree.insert(12);
        tree.insert(13);
        tree.insert(14);
        tree.insert(15);
        tree.insert(16);
        tree.insert(17);
        tree.insert(18);
        
        Assert.assertEquals(18, tree.size);
        Assert.assertEquals((Integer)5, tree.root.value);
        testTreeBSTProperties(tree.root);
    }

    @Test
    public void testInsertSortedDesc() {
        ScapegoatTree tree = new ScapegoatTree();
        tree.insert(18);
        tree.insert(17);
        tree.insert(16);
        tree.insert(15);
        tree.insert(14);
        tree.insert(13);
        tree.insert(12);
        tree.insert(11);
        tree.insert(10);
        tree.insert(9);
        tree.insert(8);
        tree.insert(7);
        tree.insert(6);
        tree.insert(5);
        tree.insert(4);
        tree.insert(3);
        tree.insert(2);
        tree.insert(1);
        tree.printTree();
        
        Assert.assertEquals(18, tree.size);
        Assert.assertEquals((Integer)12, tree.root.value);
        testTreeBSTProperties(tree.root);
    }
    
    
    @Test
    public void testDeleteSortedDesc() {
        ScapegoatTree tree = new ScapegoatTree();
        tree.insert(18);
        tree.insert(17);
        tree.insert(16);
        tree.insert(15);
        tree.insert(14);
        tree.insert(13);
        tree.insert(12);
        tree.insert(11);
        tree.insert(10);
        tree.insert(9);
        tree.insert(8);
        tree.insert(7);
        tree.insert(6);
        tree.insert(5);
        tree.insert(4);
        tree.insert(3);
        tree.insert(2);
        tree.insert(1);
        tree.printTree();
        
        tree.delete(18);
        tree.delete(17);
        tree.delete(15);
        tree.delete(14);
        tree.delete(12);
        tree.delete(10);
        tree.delete(8);
        tree.printTree();
        
        Assert.assertEquals(11, tree.size);
        Assert.assertEquals((Integer)13, tree.root.value);
        testTreeBSTProperties(tree.root);
    }
    
    @Test
    public void testBuildBigTree() {
        ScapegoatTree tree = new ScapegoatTree(0.95);
        for (int i = 0; i < 100; i++) {
            tree.insert(i);
        }
        tree.printTree();
        Assert.assertEquals(100, tree.size);
        testTreeBSTProperties(tree.root);
        
        for (int i = 0; i < 50; i++) {
            tree.delete(i);
        }
        tree.printTree();
        Assert.assertEquals(50, tree.size);
        testTreeBSTProperties(tree.root);
    }
    
    
    @Test
    public void testGetSubtreeSize() {
        Node root = new Node(4, null, null, null);
        Node rightChild = new Node(6, root, null, null);
        root.right = rightChild;
        Node leftGrandChild = new Node(5, rightChild, null, null);
        Node rightGrandChild = new Node(7, rightChild, null, null);
        rightChild.left = leftGrandChild;
        rightChild.right = rightGrandChild;
        ScapegoatTree tree = new ScapegoatTree();
        Assert.assertEquals(tree.getSubtreeSize(root), 4);
    }
    
    @Test
    public void testFindScapegoat() {
        // TODO
    }
    
    @Test
    public void testRebuildTree() {
        // TODO
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/SplayTreeTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.junit.Assert;
import org.junit.Test;

/**
 * Splay tree unit tests.
 * 
 * @author Ignas Lelys
 * @created Jul 19, 2011
 *
 */
public class SplayTreeTest extends BaseBSTTest {
    
    @Test
    public void testSearch() {
        SplayTree splayTree = new SplayTree();
        splayTree.insert(24);
        splayTree.insert(20);
        splayTree.insert(30);
        splayTree.insert(39);
        splayTree.insert(80);
        splayTree.insert(11);
        splayTree.search(24);
        Assert.assertEquals(splayTree.root.value, (Integer)24);
        Assert.assertEquals(splayTree.root.left.value, (Integer)11);
        Assert.assertEquals(splayTree.root.left.right.value, (Integer)20);
        Assert.assertEquals(splayTree.root.right.value, (Integer)80);
        Assert.assertEquals(splayTree.root.right.left.value, (Integer)30);
        Assert.assertEquals(splayTree.root.right.left.right.value, (Integer)39);
    }
    
    @Test
    public void testInsert() {
        SplayTree splayTree = new SplayTree();
        splayTree.insert(24);
        splayTree.insert(20);
        splayTree.insert(30);
        splayTree.insert(39);
        splayTree.insert(80);
        splayTree.insert(11);
        Assert.assertEquals(splayTree.root.value, (Integer) 11);
        Assert.assertEquals(splayTree.root.right.value, (Integer) 80);
        Assert.assertNull(splayTree.root.right.right);
        Assert.assertEquals(splayTree.root.right.left.value, (Integer) 30);
        Assert.assertEquals(splayTree.root.right.left.right.value, (Integer) 39);
        Assert.assertEquals(splayTree.root.right.left.left.value, (Integer) 20);
        Assert.assertEquals(splayTree.root.right.left.left.right.value, (Integer) 24);
        
        testTreeBSTProperties(splayTree.root);
    }
    
    @Test
    public void testDelete() {
        SplayTree splayTree = new SplayTree();
        splayTree.insert(22);
        splayTree.insert(11);
        splayTree.insert(10);
        splayTree.insert(16);
        splayTree.insert(15);
        splayTree.insert(14);
        // test insert
        Assert.assertEquals(splayTree.root.value, (Integer)14);
        Assert.assertEquals(splayTree.root.left.value, (Integer)11);
        Assert.assertEquals(splayTree.root.left.left.value, (Integer)10);
        Assert.assertEquals(splayTree.root.right.value, (Integer)15);
        Assert.assertEquals(splayTree.root.right.right.value, (Integer)16);
        Assert.assertEquals(splayTree.root.right.right.right.value, (Integer)22);
        splayTree.delete(16);
        Assert.assertEquals(splayTree.root.value, (Integer)15);
        Assert.assertEquals(splayTree.root.right.value, (Integer)22);
        Assert.assertEquals(splayTree.root.left.value, (Integer)14);
        Assert.assertEquals(splayTree.root.left.left.value, (Integer)11);
        Assert.assertEquals(splayTree.root.left.left.left.value, (Integer)10);
        splayTree.delete(22);
        Assert.assertEquals(splayTree.root.value, (Integer)15);
        Assert.assertNull(splayTree.root.right);
        Assert.assertEquals(splayTree.root.left.value, (Integer)14);
        Assert.assertEquals(splayTree.root.left.left.value, (Integer)11);
        Assert.assertEquals(splayTree.root.left.left.left.value, (Integer)10);
        splayTree.delete(15);
        Assert.assertEquals(splayTree.root.value, (Integer)14);
        Assert.assertNull(splayTree.root.right);
        Assert.assertEquals(splayTree.root.left.value, (Integer)11);
        Assert.assertEquals(splayTree.root.left.left.value, (Integer)10);
        
        testTreeBSTProperties(splayTree.root);
    }

    @Test
    public void testSplayZig() {
        SplayTree splayTree = new SplayTree();
        Node root = new Node(15, null, null, null);
        splayTree.root = root;
        Node left = new Node(10, root, null, null);
        root.left = left;
        splayTree.splay(left);
        Assert.assertEquals(splayTree.root.value, (Integer) 10);
        Assert.assertEquals(splayTree.root.right.value, (Integer) 15);
        splayTree.splay(splayTree.root.right);
        Assert.assertEquals(splayTree.root.value, (Integer) 15);
        Assert.assertEquals(splayTree.root.left.value, (Integer) 10);
    }

    @Test
    public void testSplayZigZig() {
        SplayTree splayTree = new SplayTree();
        Node root = new Node(15, null, null, null);
        splayTree.root = root;
        Node left = new Node(10, root, null, null);
        Node leftleft = new Node(5, left, null, null);
        left.left = leftleft;
        root.left = left;
        splayTree.splay(leftleft);
        Assert.assertEquals(splayTree.root.value, (Integer) 5);
        Assert.assertEquals(splayTree.root.right.value, (Integer) 10);
        Assert.assertEquals(splayTree.root.right.right.value, (Integer) 15);
        splayTree.splay(splayTree.root.right.right);
        Assert.assertEquals(splayTree.root.value, (Integer) 15);
        Assert.assertEquals(splayTree.root.left.value, (Integer) 10);
        Assert.assertEquals(splayTree.root.left.left.value, (Integer) 5);
    }

    @Test
    public void testSplayZigZag() {
        SplayTree splayTree = new SplayTree();
        Node root = new Node(15, null, null, null);
        splayTree.root = root;
        Node left = new Node(10, root, null, null);
        Node leftright = new Node(12, left, null, null);
        left.right = leftright;
        root.left = left;
        // zig zag left-right
        splayTree.splay(leftright);
        Assert.assertEquals(splayTree.root.value, (Integer) 12);
        Assert.assertEquals(splayTree.root.right.value, (Integer) 15);
        Assert.assertEquals(splayTree.root.left.value, (Integer) 10);
        // zig zag from other side (right-left)
        splayTree.root.right.left = new Node(13, splayTree.root.right, null, null);
        splayTree.splay(splayTree.root.right.left);
        Assert.assertEquals(splayTree.root.value, (Integer) 13);
        Assert.assertEquals(splayTree.root.left.value, (Integer) 12);
        Assert.assertEquals(splayTree.root.right.value, (Integer) 15);
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/TreapTest.java
================================================
package org.intelligentjava.algos.trees;

import org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;
import org.intelligentjava.algos.trees.Treap.TreapNode;
import org.junit.Assert;
import org.junit.Test;

/**
 * Treap tests.
 * 
 * @author Ignas Lelys
 * @created Jul 26, 2011
 * 
 */
public class TreapTest extends BaseBSTTest {

    // TODO check if after rotation other Nodes can destroy heap property (it shouldn't i think)
    @Test
    public void testInsert() {
        Treap treap = new Treap() {
            @Override
            protected Node createNode(int value, Node parent, Node left, Node right) {
                return new TreapNode(value, parent, left, right, Integer.MAX_VALUE); // create max integer priority instead of random
            }
        };
        TreapNode root = new TreapNode(20, null, null, null, 100);
        TreapNode rootLeft = new TreapNode(15, root, null, null, 99);
        TreapNode rootRight = new TreapNode(25, root, null, null, 98);
        root.left = rootLeft;
        root.right = rootRight;
        TreapNode rootLeftLeft = new TreapNode(14, rootLeft, null, null, 97);
        TreapNode rootLeftRight = new TreapNode(17, rootLeft, null, null, 96);
        rootLeft.left = rootLeftLeft;
        rootLeft.right = rootLeftRight;
        treap.root = root;
        treap.insert(16);
        // this should go to root because createNode sets highest priority
        Assert.assertEquals(treap.size, 1); // because only one insert invoked (other nodes were added manually)
        Assert.assertEquals(treap.root.value, (Integer) 16);
        Assert.assertEquals(treap.root.right.value, (Integer) 20);
        Assert.assertEquals(treap.root.right.right.value, (Integer) 25);
        Assert.assertEquals(treap.root.right.left.value, (Integer) 17);
        Assert.assertEquals(treap.root.left.value, (Integer) 15);
        Assert.assertEquals(treap.root.left.left.value, (Integer) 14);
    }
    
    @Test
    public void testDelete() {
        Treap treap = new Treap();
        TreapNode root = new TreapNode(20, null, null, null, 100);
        TreapNode rootLeft = new TreapNode(15, root, null, null, 99);
        TreapNode rootRight = new TreapNode(25, root, null, null, 98);
        root.left = rootLeft;
        root.right = rootRight;
        TreapNode rootLeftLeft = new TreapNode(14, rootLeft, null, null, 97);
        TreapNode rootLeftRight = new TreapNode(17, rootLeft, null, null, 96);
        rootLeft.left = rootLeftLeft;
        rootLeft.right = rootLeftRight;
        treap.root = root;
        Node delete = treap.delete(20);
        Assert.assertEquals(delete.value, (Integer) 15); 
    }
    
    @Test
    public void testHeapPropertyAfterInsertAndDelete() {
        Treap treap = new Treap();
        treap.insert(23);
        treap.insert(13);
        treap.insert(56);
        treap.insert(1);
        treap.insert(34);
        treap.insert(56);
        treap.insert(33);
        treap.insert(21);
        treap.insert(65);
        treap.insert(45);
        treap.insert(76);
        treap.insert(99);
        treap.insert(43);
        treap.insert(46);
        treap.insert(77);
        treap.insert(88);
        treap.insert(102);
        treap.insert(18);
        treap.insert(123);
        treap.insert(256);
        treap.insert(111);
        treap.insert(331);
        treap.insert(2);
        treap.insert(3);
        treap.insert(4);
        
        Assert.assertEquals(25, treap.size);
        testTreeBSTProperties(treap.root);
        testHeapProperties(treap.root);        
        treap.delete(1);
        treap.delete(45);
        treap.delete(43);
        treap.delete(331);
        treap.delete(3);

        Assert.assertEquals(20, treap.size);
        testTreeBSTProperties(treap.root);
        testHeapProperties(treap.root);        
    }
    
    private void testHeapProperties(Node entry) {
        if (entry != null) {
            // test heap properties and BST properties
            if (entry.left != null) {
                Assert.assertTrue(((TreapNode)entry).priority >= ((TreapNode)entry.left).priority);
            }
            if (entry.right != null) {
                Assert.assertTrue(((TreapNode)entry).priority >= ((TreapNode)entry.right).priority);
            }
            testHeapProperties(entry.left);
            testHeapProperties(entry.right);
        }
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/ArrayUtilsTest.java
================================================
package org.intelligentjava.algos.trees.utils;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created May 3, 2011
 *
 */
public class ArrayUtilsTest {
    
    @Test
    public void testSwap() {
        int[] testArr = {1, 2, 4, 3};
        ArrayUtils.swap(testArr, 2, 3);
        Assert.assertEquals(testArr[0], 1);
        Assert.assertEquals(testArr[1], 2);
        Assert.assertEquals(testArr[2], 3);
        Assert.assertEquals(testArr[3], 4);
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/HeapUtilsTest.java
================================================
package org.intelligentjava.algos.trees.utils;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created Apr 18, 2011
 *
 */
public class HeapUtilsTest {
    
    @Test
    public void testBuildHeap() {
        int[] testData = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
        int[] expectedData = {16, 14, 10, 8, 7, 9, 3, 2, 4, 1};
        HeapUtils.buildMaxHeap(testData);
        for (int i = 0; i < testData.length; i++) {
            Assert.assertTrue(testData[i] == expectedData[i]);
        }
    }
    
    @Test
    public void testMaxHeapify() {
        int[] testData = {16, 4, 10, 14, 7, 9, 3, 2, 8, 1};
        int[] expectedData = {16, 14, 10, 8, 7, 9, 3, 2, 4, 1};
        HeapUtils.maxHeapify(testData, 1);
        for (int i = 0; i < testData.length; i++) {
            Assert.assertTrue(testData[i] == expectedData[i]);
        }
    }

}


================================================
FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/MathUtilsTest.java
================================================
package org.intelligentjava.algos.trees.utils;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author Ignas Lelys
 * @created May 3, 2011
 *
 */
public class MathUtilsTest {
    
    @Test
    public void testGetDigitFromNumber() {
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 0), 5);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 1), 4);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 2), 4);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 3), 3);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 4), 3);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 5), 2);
        Assert.assertEquals(MathUtils.getDigitFromNumber(2233445, 6), 2);
    }

}
Download .txt
gitextract_wjyganpj/

├── .gitignore
├── LICENSE
├── README.md
└── Trees/
    ├── .gitignore
    ├── pom.xml
    └── src/
        ├── main/
        │   └── java/
        │       └── org/
        │           └── intelligentjava/
        │               └── algos/
        │                   ├── simplestructures/
        │                   │   ├── LinkedList.java
        │                   │   ├── PriorityQueue.java
        │                   │   ├── Queue.java
        │                   │   └── Stack.java
        │                   └── trees/
        │                       ├── AVLTree.java
        │                       ├── AbstractBinarySearchTree.java
        │                       ├── AbstractSelfBalancingBinarySearchTree.java
        │                       ├── BinarySearchTree.java
        │                       ├── RedBlackTree.java
        │                       ├── ScapegoatTree.java
        │                       ├── SplayTree.java
        │                       ├── Treap.java
        │                       ├── benchmark/
        │                       │   ├── TreesDeleteBenchmark.java
        │                       │   ├── TreesInsertRandomBenchmark.java
        │                       │   ├── TreesInsertSortedBenchmark.java
        │                       │   ├── TreesSearchBenchmark.java
        │                       │   └── TreesSearchSameElementsBenchmark.java
        │                       ├── exceptions/
        │                       │   └── QueueOverflowException.java
        │                       ├── main/
        │                       │   └── Main.java
        │                       └── utils/
        │                           ├── ArrayUtils.java
        │                           ├── HeapUtils.java
        │                           └── MathUtils.java
        └── test/
            └── java/
                └── org/
                    └── intelligentjava/
                        └── algos/
                            ├── simplestructures/
                            │   ├── LinkedListTest.java
                            │   ├── PriorityQueueTest.java
                            │   ├── QueueTest.java
                            │   └── StackTest.java
                            └── trees/
                                ├── AVLTreeTest.java
                                ├── BaseBSTTest.java
                                ├── BinarySearchTreeTest.java
                                ├── RedBlackTreeTest.java
                                ├── ScapegoatTreeTest.java
                                ├── SplayTreeTest.java
                                ├── TreapTest.java
                                └── utils/
                                    ├── ArrayUtilsTest.java
                                    ├── HeapUtilsTest.java
                                    └── MathUtilsTest.java
Download .txt
SYMBOL INDEX (248 symbols across 36 files)

FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/LinkedList.java
  class LinkedList (line 11) | public class LinkedList {
    method get (line 16) | public int get(int index) {
    method insert (line 24) | public void insert(int element) {
    method delete (line 32) | public void delete(int element) {
    method search (line 46) | private Entry search(int key) {
    class Entry (line 57) | private static class Entry {
      method Entry (line 58) | public Entry(Entry previous, Entry next, int element) {

FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/PriorityQueue.java
  class PriorityQueue (line 13) | public class PriorityQueue {
    method PriorityQueue (line 19) | public PriorityQueue() {
    method insertElement (line 23) | public void insertElement(int element) {
    method changeElementValue (line 29) | public void changeElementValue(int index, int newValue) {
    method getElement (line 40) | public int getElement() {
    method removeElement (line 44) | public int removeElement() {

FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/Queue.java
  class Queue (line 12) | public class Queue {
    method Queue (line 20) | public Queue() {
    method Queue (line 25) | public Queue(int queueSize) {
    method enqueue (line 30) | public void enqueue(Object element) throws QueueOverflowException {
    method dequeue (line 42) | public Object dequeue() {
    method isEmpty (line 52) | public boolean isEmpty() {
    method isFull (line 56) | public boolean isFull() {

FILE: Trees/src/main/java/org/intelligentjava/algos/simplestructures/Stack.java
  class Stack (line 12) | public class Stack {
    method Stack (line 18) | public Stack() {
    method Stack (line 23) | public Stack(int initialSize) {
    method isEmpty (line 28) | public boolean isEmpty() {
    method push (line 32) | public void push(Object element) {
    method pop (line 40) | public Object pop() {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AVLTree.java
  class AVLTree (line 20) | public class AVLTree extends AbstractSelfBalancingBinarySearchTree {
    method insert (line 30) | @Override
    method delete (line 40) | @Override
    method createNode (line 62) | @Override
    method rebalance (line 73) | private void rebalance(AVLNode node) {
    method avlRotateLeft (line 109) | private Node avlRotateLeft(Node node) {
    method avlRotateRight (line 120) | private Node avlRotateRight(Node node) {
    method doubleRotateRightLeft (line 132) | protected Node doubleRotateRightLeft(Node node) {
    method doubleRotateLeftRight (line 141) | protected Node doubleRotateLeftRight(Node node) {
    method recomputeHeight (line 149) | private void recomputeHeight(AVLNode node) {
    method maxHeight (line 159) | private int maxHeight(AVLNode node1, AVLNode node2) {
    method updateHeight (line 175) | private static final void updateHeight(AVLNode node) {
    class AVLNode (line 191) | protected static class AVLNode extends Node {
      method AVLNode (line 194) | public AVLNode(int value, Node parent, Node left, Node right) {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AbstractBinarySearchTree.java
  class AbstractBinarySearchTree (line 14) | public abstract class AbstractBinarySearchTree {
    method createNode (line 33) | protected abstract Node createNode(int value, Node parent, Node left, ...
    method search (line 43) | public Node search(int element) {
    method insert (line 61) | public Node insert(int element) {
    method delete (line 99) | public Node delete(int element) {
    method delete (line 117) | protected Node delete(Node deleteNode) {
    method transplant (line 155) | private Node transplant(Node nodeToReplace, Node newNode) {
    method contains (line 173) | public boolean contains(int element) {
    method getMinimum (line 180) | public int getMinimum() {
    method getMaximum (line 187) | public int getMaximum() {
    method getSuccessor (line 199) | public int getSuccessor(int element) {
    method getSize (line 206) | public int getSize() {
    method printTreeInOrder (line 213) | public void printTreeInOrder() {
    method printTreePreOrder (line 220) | public void printTreePreOrder() {
    method printTreePostOrder (line 227) | public void printTreePostOrder() {
    method printTreeInOrder (line 233) | private void printTreeInOrder(Node entry) {
    method printTreePreOrder (line 243) | private void printTreePreOrder(Node entry) {
    method printTreePostOrder (line 253) | private void printTreePostOrder(Node entry) {
    method getMinimum (line 263) | protected Node getMinimum(Node node) {
    method getMaximum (line 270) | protected Node getMaximum(Node node) {
    method getSuccessor (line 277) | protected Node getSuccessor(Node node) {
    method printTree (line 298) | public void printTree() {
    method printSubtree (line 302) | public void printSubtree(Node node) {
    method printNodeValue (line 312) | private void printNodeValue(Node node) {
    method printTree (line 321) | private void printTree(Node node, boolean isRight, String indent) {
    class Node (line 339) | public static class Node {
      method Node (line 340) | public Node(Integer value, Node parent, Node left, Node right) {
      method isLeaf (line 353) | public boolean isLeaf() {
      method hashCode (line 357) | @Override
      method equals (line 365) | @Override

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/AbstractSelfBalancingBinarySearchTree.java
  class AbstractSelfBalancingBinarySearchTree (line 11) | public abstract class AbstractSelfBalancingBinarySearchTree extends Abst...
    method rotateLeft (line 19) | protected Node rotateLeft(Node node) {
    method rotateRight (line 51) | protected Node rotateRight(Node node) {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/BinarySearchTree.java
  class BinarySearchTree (line 18) | public class BinarySearchTree extends AbstractBinarySearchTree {
    method createNode (line 20) | @Override

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/RedBlackTree.java
  class RedBlackTree (line 10) | public class RedBlackTree extends AbstractSelfBalancingBinarySearchTree {
    type ColorEnum (line 12) | protected enum ColorEnum {
    method insert (line 22) | @Override
    method delete (line 37) | @Override
    method createNode (line 79) | @Override
    method getMinimum (line 87) | @Override
    method getMaximum (line 98) | @Override
    method rotateLeft (line 109) | @Override
    method rotateRight (line 139) | @Override
    method rbTreeTransplant (line 170) | private Node rbTreeTransplant(Node nodeToReplace, Node newNode) {
    method deleteRBFixup (line 185) | private void deleteRBFixup(RedBlackNode x) {
    method isBlack (line 249) | private boolean isBlack(Node node) {
    method isRed (line 253) | private boolean isRed(Node node) {
    method insertRBFixup (line 262) | private void insertRBFixup(RedBlackNode currentNode) {
    class RedBlackNode (line 323) | protected static class RedBlackNode extends Node {
      method RedBlackNode (line 326) | public RedBlackNode(Integer value, Node parent, Node left, Node righ...

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/ScapegoatTree.java
  class ScapegoatTree (line 17) | public class ScapegoatTree extends AbstractSelfBalancingBinarySearchTree {
    method ScapegoatTree (line 27) | public ScapegoatTree() {
    method ScapegoatTree (line 36) | public ScapegoatTree(double alpha) {
    method insert (line 44) | @Override
    method delete (line 72) | @Override
    method createNode (line 85) | @Override
    method findScapegoatNode (line 95) | protected Node findScapegoatNode(Node node) {
    method rebuildTree (line 121) | protected Node rebuildTree(int size, Node scapegoat) {
    method buildTree (line 150) | private Node buildTree(List<Node> nodes, int start, int end) {
    method getSibling (line 177) | private Node getSibling(Node node) {
    method getSubtreeSize (line 196) | protected int getSubtreeSize(Node node) {
    method getNodeHeight (line 211) | protected int getNodeHeight(Node node) {
    method getHAlpha (line 221) | private int getHAlpha() {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/SplayTree.java
  class SplayTree (line 10) | public class SplayTree extends AbstractSelfBalancingBinarySearchTree {
    method search (line 15) | @Override
    method insert (line 27) | @Override
    method delete (line 37) | @Override
    method createNode (line 55) | @Override
    method splay (line 66) | protected void splay(Node node) {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/Treap.java
  class Treap (line 14) | public class Treap extends AbstractSelfBalancingBinarySearchTree {
    method insert (line 24) | @Override
    method delete (line 47) | @Override
    method createNode (line 62) | @Override
    method rotateDown (line 74) | private Node rotateDown(TreapNode node) {
    class TreapNode (line 108) | protected static class TreapNode extends Node {
      method TreapNode (line 111) | public TreapNode(int value, Node parent, Node left, Node right, int ...

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesDeleteBenchmark.java
  class TreesDeleteBenchmark (line 27) | @OutputTimeUnit(TimeUnit.MILLISECONDS)
    method setup (line 38) | @Setup(Level.Trial)
    method timeJDKTreeSet (line 46) | @Benchmark
    method timeDeleteRedBlackTree (line 60) | @Benchmark
    method timeDeleteAVLTree (line 74) | @Benchmark
    method timeDeleteSplayTree (line 88) | @Benchmark
    method timeDeleteTreap (line 102) | @Benchmark
    method timeDeleteScapegoat0_6Tree (line 116) | @Benchmark
    method timeDeleteScapegoat0_75Tree (line 130) | @Benchmark
    method timeDeleteScapegoat0_9Tree (line 144) | @Benchmark
    method main (line 158) | public static void main(String[] args) throws RunnerException {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertRandomBenchmark.java
  class TreesInsertRandomBenchmark (line 27) | @OutputTimeUnit(TimeUnit.MILLISECONDS)
    method setup (line 38) | @Setup(Level.Trial)
    method timeJDKTreeSet (line 46) | @SuppressWarnings({ "unchecked", "rawtypes" })
    method timeRedBlackTree (line 56) | @Benchmark
    method timeAVLTree (line 65) | @Benchmark
    method timeSplayTree (line 74) | @Benchmark
    method timeTreap (line 83) | @Benchmark
    method timeScapegoat0_6Tree (line 92) | @Benchmark
    method timeScapegoat0_75Tree (line 101) | @Benchmark
    method timeScapegoat0_9Tree (line 110) | @Benchmark
    method main (line 119) | public static void main(String[] args) throws RunnerException {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertSortedBenchmark.java
  class TreesInsertSortedBenchmark (line 24) | @OutputTimeUnit(TimeUnit.MILLISECONDS)
    method timeJDKTreeSet (line 31) | @SuppressWarnings({ "unchecked", "rawtypes" })
    method timeRedBlackTree (line 41) | @Benchmark
    method timeAVLTree (line 50) | @Benchmark
    method timeSplayTree (line 59) | @Benchmark
    method timeTreap (line 68) | @Benchmark
    method timeScapegoat0_6Tree (line 77) | @Benchmark
    method timeScapegoat0_75Tree (line 86) | @Benchmark
    method timeScapegoat0_9Tree (line 95) | @Benchmark
    method main (line 104) | public static void main(String[] args) throws RunnerException {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchBenchmark.java
  class TreesSearchBenchmark (line 28) | @SuppressWarnings("unchecked")
    method setup (line 48) | @Setup(Level.Trial)
    method timeJDKTreeSet (line 81) | @Benchmark
    method timeSearchRedBlackTree (line 90) | @Benchmark
    method timeSearchAVLTree (line 99) | @Benchmark
    method timeSearchSplayTree (line 108) | @Benchmark
    method timeSearchTreap (line 117) | @Benchmark
    method timeSearchScapegoat0_6Tree (line 126) | @Benchmark
    method timeSearchScapegoat0_75Tree (line 135) | @Benchmark
    method timeSearchScapegoat0_9Tree (line 144) | @Benchmark
    method main (line 153) | public static void main(String[] args) throws RunnerException {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchSameElementsBenchmark.java
  class TreesSearchSameElementsBenchmark (line 28) | @SuppressWarnings("unchecked")
    method setup (line 48) | @Setup(Level.Trial)
    method timeJDKTreeSet (line 80) | @Benchmark
    method timeSearchRedBlackTree (line 89) | @Benchmark
    method timeSearchAVLTree (line 98) | @Benchmark
    method timeSearchSplayTree (line 107) | @Benchmark
    method timeSearchTreap (line 116) | @Benchmark
    method timeSearchScapegoat0_6Tree (line 125) | @Benchmark
    method timeSearchScapegoat0_75Tree (line 134) | @Benchmark
    method timeSearchScapegoat0_9Tree (line 143) | @Benchmark
    method main (line 152) | public static void main(String[] args) throws RunnerException {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/exceptions/QueueOverflowException.java
  class QueueOverflowException (line 10) | public class QueueOverflowException extends Exception {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/main/Main.java
  class Main (line 7) | public class Main {
    method main (line 11) | public static void main(String[] args) {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/ArrayUtils.java
  class ArrayUtils (line 10) | public class ArrayUtils {
    method swap (line 22) | public static void swap(int[] data, int elementIndex1, int elementInde...
    method selectNthSmallestElement (line 38) | public static int selectNthSmallestElement(int[] data, int n) {
    method selectNthSmallestElement (line 51) | public static int selectNthSmallestElement(int[] data, int sublistStar...
    method partition (line 75) | private static int partition(int[] data, int sublistStartIndex, int su...

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/HeapUtils.java
  class HeapUtils (line 14) | public class HeapUtils {
    method buildMaxHeap (line 20) | public static void buildMaxHeap(int[] data) {
    method maxHeapify (line 33) | public static void maxHeapify(int[] data, int index) {
    method maxHeapify (line 42) | public static void maxHeapify(int[] data, int index, int heapSize) {
    method getParent (line 58) | public static int getParent(int leafIndex) {
    method getLeftLeaf (line 69) | private static int getLeftLeaf(int parentIndex) {
    method getRightLeaf (line 80) | private static int getRightLeaf(int parentIndex) {

FILE: Trees/src/main/java/org/intelligentjava/algos/trees/utils/MathUtils.java
  class MathUtils (line 10) | public class MathUtils {
    method getDigitFromNumber (line 20) | public static int getDigitFromNumber(int number, int digitIndex) {
    method getMax (line 32) | public static int getMax(int first, int second) {
    method logarithm (line 39) | public static double logarithm(double base, double a) {

FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/LinkedListTest.java
  class LinkedListTest (line 11) | public class LinkedListTest {
    method testInsertDelete (line 13) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/PriorityQueueTest.java
  class PriorityQueueTest (line 8) | public class PriorityQueueTest {

FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/QueueTest.java
  class QueueTest (line 12) | public class QueueTest {
    method testEnqueueDequeue (line 14) | @Test
    method testIsEmpty (line 25) | @Test
    method testIsFull (line 33) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/simplestructures/StackTest.java
  class StackTest (line 11) | public class StackTest {
    method testPushPop (line 13) | @Test
    method testIsEmpty (line 24) | @Test
    method testMoreThan10 (line 36) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/AVLTreeTest.java
  class AVLTreeTest (line 15) | public class AVLTreeTest extends BaseBSTTest {
    method testDelete (line 17) | @Test
    method testInsert (line 35) | @Test
    method testRotateLeft (line 58) | @Test
    method testRotateRight (line 82) | @Test
    method testDoubleRotateRightLeft (line 106) | @Test
    method testDoubleRotateLeftRight (line 130) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/BaseBSTTest.java
  class BaseBSTTest (line 12) | public class BaseBSTTest {
    method testTreeBSTProperties (line 14) | protected void testTreeBSTProperties(Node entry) {

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/BinarySearchTreeTest.java
  class BinarySearchTreeTest (line 13) | public class BinarySearchTreeTest extends BaseBSTTest {
    method testInsertDelete (line 15) | @Test
    method testSize (line 34) | @Test
    method testMinimumMaximum (line 47) | @Test
    method testGetSuccessor (line 58) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/RedBlackTreeTest.java
  class RedBlackTreeTest (line 19) | public class RedBlackTreeTest {
    method testInsertionFixupColoring (line 20) | @Test
    method testInsert (line 31) | @Test
    method testSimpleDelete (line 56) | @Test
    method testDelete (line 72) | @Test
    method testTreeBSTProperties (line 101) | private void testTreeBSTProperties(Node entry) {

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/ScapegoatTreeTest.java
  class ScapegoatTreeTest (line 14) | public class ScapegoatTreeTest extends BaseBSTTest {
    method testInsertSorted (line 17) | @Test
    method testInsertSortedDesc (line 44) | @Test
    method testDeleteSortedDesc (line 73) | @Test
    method testBuildBigTree (line 110) | @Test
    method testGetSubtreeSize (line 129) | @Test
    method testFindScapegoat (line 142) | @Test
    method testRebuildTree (line 147) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/SplayTreeTest.java
  class SplayTreeTest (line 14) | public class SplayTreeTest extends BaseBSTTest {
    method testSearch (line 16) | @Test
    method testInsert (line 34) | @Test
    method testDelete (line 54) | @Test
    method testSplayZig (line 91) | @Test
    method testSplayZigZig (line 106) | @Test
    method testSplayZigZag (line 125) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/TreapTest.java
  class TreapTest (line 15) | public class TreapTest extends BaseBSTTest {
    method testInsert (line 18) | @Test
    method testDelete (line 47) | @Test
    method testHeapPropertyAfterInsertAndDelete (line 64) | @Test
    method testHeapProperties (line 107) | private void testHeapProperties(Node entry) {

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/ArrayUtilsTest.java
  class ArrayUtilsTest (line 11) | public class ArrayUtilsTest {
    method testSwap (line 13) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/HeapUtilsTest.java
  class HeapUtilsTest (line 11) | public class HeapUtilsTest {
    method testBuildHeap (line 13) | @Test
    method testMaxHeapify (line 23) | @Test

FILE: Trees/src/test/java/org/intelligentjava/algos/trees/utils/MathUtilsTest.java
  class MathUtilsTest (line 11) | public class MathUtilsTest {
    method testGetDigitFromNumber (line 13) | @Test
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (140K chars).
[
  {
    "path": ".gitignore",
    "chars": 118,
    "preview": "Trees/.classpath\nTrees/.project\nTrees/.settings/org.eclipse.jdt.core.prefs\nTrees/.settings/org.eclipse.m2e.core.prefs\n"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 342,
    "preview": "# BinarySearchTrees\nJava binary search trees implementations and tests: AVL Tree, Red black tree, Scapegoat tree, Splay "
  },
  {
    "path": "Trees/.gitignore",
    "chars": 9,
    "preview": "/target/\n"
  },
  {
    "path": "Trees/pom.xml",
    "chars": 3998,
    "preview": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocat"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/simplestructures/LinkedList.java",
    "chars": 1789,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\n/**\n * Standard simple non circular doubly linked Linked List imple"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/simplestructures/PriorityQueue.java",
    "chars": 1371,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport org.intelligentjava.algos.trees.utils.ArrayUtils;\nimport org"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/simplestructures/Queue.java",
    "chars": 1390,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport org.intelligentjava.algos.trees.exceptions.QueueOverflowExce"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/simplestructures/Stack.java",
    "chars": 842,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport java.util.Arrays;\n\n/**\n * Stack.\n * \n * @author Ignas Lelys\n"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/AVLTree.java",
    "chars": 6932,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.utils.MathUtils;\n\n/**\n * AVL tree imple"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/AbstractBinarySearchTree.java",
    "chars": 11177,
    "preview": "package org.intelligentjava.algos.trees;\n\n/**\n * Abstract binary search tree implementation. Its basically fully impleme"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/AbstractSelfBalancingBinarySearchTree.java",
    "chars": 1946,
    "preview": "package org.intelligentjava.algos.trees;\n\n/**\n * Abstract class for self balancing binary search trees. Contains some me"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/BinarySearchTree.java",
    "chars": 851,
    "preview": "package org.intelligentjava.algos.trees;\n\n/**\n * Binary search tree implementation.\n * \n * In computer science, a binary"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/RedBlackTree.java",
    "chars": 12770,
    "preview": "package org.intelligentjava.algos.trees;\n\n/**\n * Red-Black tree implementation. From Introduction to Algorithms 3rd edit"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/ScapegoatTree.java",
    "chars": 6387,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Stack;\n\nim"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/SplayTree.java",
    "chars": 3748,
    "preview": "package org.intelligentjava.algos.trees;\n\n/**\n * Splay tree implementation.\n * \n * @author Ignas Lelys\n * @created Jul 1"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/Treap.java",
    "chars": 3913,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport java.util.Random;\n\n/**\n * Treap is randomized binary search tree. Easie"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesDeleteBenchmark.java",
    "chars": 4748,
    "preview": "package org.intelligentjava.algos.trees.benchmark;\n\nimport java.util.Random;\nimport java.util.TreeSet;\nimport java.util."
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertRandomBenchmark.java",
    "chars": 3692,
    "preview": "package org.intelligentjava.algos.trees.benchmark;\n\nimport java.util.Random;\nimport java.util.TreeSet;\nimport java.util."
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesInsertSortedBenchmark.java",
    "chars": 3173,
    "preview": "package org.intelligentjava.algos.trees.benchmark;\n\nimport java.util.TreeSet;\nimport java.util.concurrent.TimeUnit;\n\nimp"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchBenchmark.java",
    "chars": 5100,
    "preview": "package org.intelligentjava.algos.trees.benchmark;\n\nimport java.util.Random;\nimport java.util.TreeSet;\nimport java.util."
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/benchmark/TreesSearchSameElementsBenchmark.java",
    "chars": 5155,
    "preview": "package org.intelligentjava.algos.trees.benchmark;\n\nimport java.util.Random;\nimport java.util.TreeSet;\nimport java.util."
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/exceptions/QueueOverflowException.java",
    "chars": 262,
    "preview": "package org.intelligentjava.algos.trees.exceptions;\n\n/**\n * Exception when queue overflow.\n * \n * @author Ignas Lelys\n *"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/main/Main.java",
    "chars": 876,
    "preview": "package org.intelligentjava.algos.trees.main;\n\nimport java.util.Random;\n\nimport org.intelligentjava.algos.trees.RedBlack"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/utils/ArrayUtils.java",
    "chars": 2946,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\n/**\n * Helper class which helps to work with arrays.\n * \n * @author Igna"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/utils/HeapUtils.java",
    "chars": 2270,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\n/**\n * Utils for working with heap data structure. Heap is a tree like d"
  },
  {
    "path": "Trees/src/main/java/org/intelligentjava/algos/trees/utils/MathUtils.java",
    "chars": 1058,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\n/**\n * Some syntactic sugar for math operations.\n * \n * @author Ignas Le"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/simplestructures/LinkedListTest.java",
    "chars": 1126,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author Ign"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/simplestructures/PriorityQueueTest.java",
    "chars": 147,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\n/**\n * @author Ignas Lelys\n * @created May 4, 2011\n *\n */\npublic cl"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/simplestructures/QueueTest.java",
    "chars": 1560,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport org.intelligentjava.algos.trees.exceptions.QueueOverflowExce"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/simplestructures/StackTest.java",
    "chars": 1090,
    "preview": "package org.intelligentjava.algos.simplestructures;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author Ign"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/AVLTreeTest.java",
    "chars": 6047,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AVLTree.AVLNode;\nimport org.intelligent"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/BaseBSTTest.java",
    "chars": 747,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;\nimport o"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/BinarySearchTreeTest.java",
    "chars": 2032,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * Tests for simple unbal"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/RedBlackTreeTest.java",
    "chars": 4637,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;\nimport o"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/ScapegoatTreeTest.java",
    "chars": 3888,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;\nimport o"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/SplayTreeTest.java",
    "chars": 6201,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;\nimport o"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/TreapTest.java",
    "chars": 4392,
    "preview": "package org.intelligentjava.algos.trees;\n\nimport org.intelligentjava.algos.trees.AbstractBinarySearchTree.Node;\nimport o"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/utils/ArrayUtilsTest.java",
    "chars": 492,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author Ignas Le"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/utils/HeapUtilsTest.java",
    "chars": 882,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author Ignas Le"
  },
  {
    "path": "Trees/src/test/java/org/intelligentjava/algos/trees/utils/MathUtilsTest.java",
    "chars": 769,
    "preview": "package org.intelligentjava.algos.trees.utils;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author Ignas Le"
  }
]

About this extraction

This page contains the full source code of the ignl/BinarySearchTrees GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (129.1 KB), approximately 32.3k tokens, and a symbol index with 248 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!