All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.ojil.algorithm.ThreadedBinaryTree Maven / Gradle / Ivy

There is a newer version: 0.0.11
Show newest version
/**
 * Copyright 2008 by Jon A. Webb
 *     This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the Lesser GNU General Public License
 *    along with this program.  If not, see .
 *
 */

package com.github.ojil.algorithm;

import java.util.Vector;

import com.github.ojil.core.ImageError;

/**
 * ThreadedBinaryTree is an implements threaded binary trees, as the name
 * implies. The implementation of threaded binary trees here was guided by the
 * tutorial at  http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_bst1.aspx#
 * thread. 
 * 

* Threaded binary trees are like normal (unbalanced) binary trees except that * nodes which have no right successor have a pointer to their inorder inserted * in the right pointer. This makes it possible to perform an inorder traversal * starting at any node without doing a full traversal of the tree. *

* The use of threaded binary trees in JJIL is to make it possible to add() a * new element to the tree in average log n time and then to traverse from any * node to any other node in time equal to the number of nodes between the two * nodes. If I'd used a normal binary tree to do the traversal the time would * have been equal to the number of nodes in the tree. Both are O(n) but the * number of nodes between the two nodes being traversed should be a fraction of * the total number of nodes in the tree. * * @author webb * */ public class ThreadedBinaryTree { /** * boolThread identifies the case where the right pointer is the inorder * successor, not the right descendant. */ private boolean boolThread = false; /** * key is the comparison key stored at the node. */ private final ComparableJ2me key; /** * left is a pointer to the left side of the tree, or null if there is no * left descendant. */ private ThreadedBinaryTree left = null; /** * right is a pointer to the right side of the tree or the inorder successor * if there is no right descendant. */ private ThreadedBinaryTree right = null; /** * value associated with this node */ private Object value = null; /** * Create a new ThreadedBinaryTree node without descendants or an inorder * successor. * * @param key * the key for comparison. */ public ThreadedBinaryTree(final ComparableJ2me key) { this.key = key; } /** * Create a new ThreadedBinaryTree node with an inorder successor. * * @param key * the key for comparison. * @param thread * the inorder successor. */ public ThreadedBinaryTree(final ComparableJ2me key, final ThreadedBinaryTree thread) { this.key = key; right = thread; boolThread = true; } /** * Add a new key to an existing ThreadedBinaryTree, returning the * ThreadedBinaryTree node with the matching key. If the key is already in * the tree we make no change to the tree and return the matching node. * Otherwise we create a new node and link it into the tree. * * @param key * the key for comparison. * @return the ThreadedBinaryTree node that matches key. * @throws ImageError * in the case of type error (key wrong type) */ public ThreadedBinaryTree add(final ComparableJ2me key) throws ImageError { final int n = key.compareTo(this.key); if (n == 0) { return this; // already in tree } else if (n < 0) { if (left != null) { return left.add(key); } else { // left descendant's inorder successor is this left = new ThreadedBinaryTree(key, this); return left; } } else { // right descendant is (almost) never null, but boolThread // indicates we're at the bottom of the tree. if ((right != null) && !boolThread) { return right.add(key); } else { // link in new right descendant. Its inorder // successor is this node's inorder successor. // This node now has a right descendant and is // no longer a threaded node. right = new ThreadedBinaryTree(key, right); boolThread = false; return right; } } } /** * Find the ThreadedBinaryTree node that matches key. * * @param key * the key for comparison * @return the ThreadedBinaryTree node which matches key, or null if nothing * does. * @throws ImageError * in the case of type error (key wrong type) */ public ThreadedBinaryTree find(final ComparableJ2me key) throws ImageError { final int n = this.key.compareTo(key); if (n == 0) { return this; // found } else if (n > 0) { // this is > than the key we are searching for. The match // is either to the left or not there if (left != null) { return left.find(key); } else { return null; // not found } } else { // this is < than the key we are searching for. The match // is either to the right or not there. if ((right != null) && !boolThread) { return right.find(key); } else { return null; // not found } } } /** * Find the ThreadedBinaryTree node with the largest key which is @le; the * given key. * * @param key * the key to compare * @return the ThreadedBinaryTree node which matches key, or null if nothing * does. * @throws ImageError * in the case of type error (key wrong type) */ public ThreadedBinaryTree findNearest(final ComparableJ2me key) throws ImageError { final int n = this.key.compareTo(key); if (n == 0) { return this; // found exact match } else if (n < 0) { // this is < the key we are searching for. The best match is // the match to the right if there is one, otherwise this. if ((right != null) && !boolThread) { // the nearest is either this element, or down and to the // right final ThreadedBinaryTree tbtRight = right.findNearest(key); if (tbtRight == null) { return this; } else { return tbtRight; } } else { // nothing to the right return this; } } else { // this is greater than the key. the nearest is either down and // to the left, or nothing if (left != null) { return left.findNearest(key); } else { return null; // not found } } } /** * Perform an inorder traversal of the tree from this to end and return a * Vector containing all the nodes traversed, in the order of traversal, or * null if there is no inorder path starting at this and ending at end. * * @param end * the end of the path. * @return a Vector containing all the nodes traversed, in the order of * traversal, or null if there is no path. */ @SuppressWarnings("rawtypes") public Vector inorderTraverse(final ThreadedBinaryTree end) { final Vector v = new Vector(); // Start traversal with empty Vector. The traversal // is initialized with bFollowedThread = false because // we want to do inorder traversal from this node. return this.inorderTraverse(v, false, end); } /** * Helper function for actually doing the traversal. Appends the next node * traversed to the end of v and continues the traversal recursively. * * @param v * the input Vector; this becomes the output on a successful * traversal. * @param bFollowedThread * if true indicates we followed a thread (an upward link) to get * to this node. * @param end * the ending node for the traversal. * @return the parameter v with the nodes traversed from this to end * appended to it, if there is a path; otherwise, null. */ @SuppressWarnings({ "rawtypes", "unchecked" }) private Vector inorderTraverse(final Vector v, final boolean bFollowedThread, final ThreadedBinaryTree end) { if (!bFollowedThread) { // last traversal was downwards, not a threaded link. // this means that we should continue down and to the left. if (left != null) { return left.inorderTraverse(v, false, end); } else { // can't continue down and to the left. Add current // node to the traversal list and continue right, // either continuing down or up following thread. v.addElement(this); if (this == end) { // success return v; } else { return right.inorderTraverse(v, boolThread, end); } } } else { // last traversal was upwards (thread) link. We must // add current node to traversal list and continue // to the right (following descendant or thread). v.addElement(this); if (this == end) { // success return v; } if (right != null) { return right.inorderTraverse(v, boolThread, end); } else { // there is no right successor, so we reached end of tree // without finding end. There is no path. return null; } } } /** * Return the key associated with this node. * * @return the key associated with this node. */ public ComparableJ2me getKey() { return key; } /** * Return the current value associated with this node. * * @return the value associated with this node. */ public Object getValue() { return value; } /** * Change the value associated with this node. * * @param value * the new value to associate with this node. */ public void setValue(final Object value) { this.value = value; } /** * Implement toString. */ @Override public String toString() { String szRes = super.toString() + "(key="; if (key != null) { szRes += key.toString(); } else { szRes += "null"; } szRes += ",left="; if (left != null) { szRes += left.toString(); } else { szRes += "null"; } szRes += ",right="; if (boolThread) { szRes += "thread," + ((Object) right).toString(); } else if (right == null) { szRes += "null"; } else { szRes += right.toString(); } szRes += ")"; return szRes; } // Test code // Tries all possible ThreadedBinaryTrees with elements 0-5 and verifies // inorder traversal from 0-5. // public int valueOf() { // return this.n; // } // } // try { // for (int i = 0; i<6; i++) { // for (int j = 0; j<6; j++) { // if (i != j) for (int k=0; k<6; k++) { // if (k != i && k != j) for (int l=0; l<6; l++) { // if (l != k && l != j && l != i) for (int m=0; m<6; m++) { // if (m != l && m != k && m != j && m != i) for (int n=0; n<6; n++) { // if (n != m && n != l && n != k && n != j && n != i) { // ThreadedBinaryTree t = new ThreadedBinaryTree(new ComparableInt(i)); // t.add(new ComparableInt(j)); // t.add(new ComparableInt(k)); // t.add(new ComparableInt(l)); // t.add(new ComparableInt(m)); // t.add(new ComparableInt(n)); // ThreadedBinaryTree tbt0 = t.find(new ComparableInt(0)); // ThreadedBinaryTree tbt5 = t.find(new ComparableInt(5)); // Vector v = tbt0.inorderTraverse(tbt5); // for (int o = 0; o<6; o++) { // ThreadedBinaryTree tbt = (ThreadedBinaryTree)v.elementAt(o); // ComparableInt ci = (ComparableInt)tbt.getKey(); // if (ci.valueOf() != o) { // Vector u = tbt0.inorderTraverse(tbt5); // int error = 1; // } // // } // } // } // } // } // } // } // } // } catch (jjil.core.Error e) { // // } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy