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 ================================================ 4.0.0 org.intelligentjava Trees 0.0.1-SNAPSHOT org.openjdk.jmh jmh-core 1.21 org.openjdk.jmh jmh-generator-annprocess 1.21 provided junit junit 4.11 org.apache.maven.plugins maven-compiler-plugin 3.1 1.7 1.7 1.7 org.apache.maven.plugins maven-shade-plugin 2.2 package shade benchmarks org.openjdk.jmh.Main maven-clean-plugin 2.5 maven-deploy-plugin 2.8.1 maven-install-plugin 2.5.1 maven-jar-plugin 2.4 maven-javadoc-plugin 2.9.1 maven-resources-plugin 2.6 maven-site-plugin 3.3 maven-source-plugin 2.2.1 maven-surefire-plugin 2.17 ================================================ 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(""); } 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.
* b) The right subtree of a node contains only nodes with keys greater than the node's key.
* c) Both the left and right subtrees must also be binary search trees.
* * @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 nodes = new ArrayList(); // flatten tree without recursion Node currentNode = scapegoat; boolean done = false; Stack 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 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 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); } }