CSC212 IntBST.java: A Non-Generic BST Implementation

From dftwiki3
Jump to: navigation, search

--D. Thiebaut (talk) 19:59, 28 October 2014 (EDT)



/**
 * IntBST.java
 * @author D. Thiebaut
 * All material taken, and adapted from Drozdek's
 * Data Structures and Algorithms in Java.
 * 
 */
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;

/**
 * A class implementing a BST node, with an integer key,
 * and a left and right pointer.
 * @author thiebaut
 *
 */
class IntBSTNode {
        
        public int key;
        public IntBSTNode left, right;
        IntBSTNode( int el, IntBSTNode l, IntBSTNode r ) {
                key = el;
                left = l;
                right = r;
        }
        
        IntBSTNode( int el ) {
                this( el, null, null );
        }
}

/**
 * The tree class.  Implements most useful methods.
 * @author thiebaut
 *
 */
public class IntBST {
        protected IntBSTNode root;
        
        /**
         * constructor creates an empty tree.
         */
        IntBST( ) {
                root = null;
        }
        
        protected void setRoot( IntBSTNode p ) { 
                root = p; 
        }
        
        public void clear() {
                root = null;
        }
        
        /**
         * Just use for debugging...  Recursively visits the tree
         * and display information about what it finds.
         */
        protected void debugVisit() {
                debugVisit( root );
        }
                
        protected void debugVisit( IntBSTNode p ) { 
                if ( p==null ) return;
                String leftString="has no left child", rightString = "has no right child";
                if ( p.left != null) leftString = "has " + p.left.key + " as left child";
                if ( p.right != null) rightString = "has " + p.right.key + " as right child";
                System.out.println( "Node " + p.key + ", " + leftString + ", and " + rightString );
                debugVisit( p.left );
                debugVisit( p.right );
        }
        
        /**
         * Iteratively searches for an element in the tree.  Returns the node
         * containing the element if found, or null otherwise.
         * @param el
         * @return
         */
        public IntBSTNode search( int el ) { 
                IntBSTNode p = root;
                while ( p != null ) {
                        if ( el == p.key ) 
                                return p;
                        if ( el < p.key )
                                p = p.left;
                        else 
                                p = p.right;
                }
                return null;            
        }

        /**
         * recursively searches for an element in the tree.  Returns the
         * node containing the element, or null if not found.
         * @param el
         * @return
         */
        public IntBSTNode recSearch( int el ) { 
                return recSearch( root, el );
        }
        
        private IntBSTNode recSearch( IntBSTNode p, int el ) { 
                if ( p==null )
                        return null;
                if ( el == p.key ) 
                        return p;
                if ( el < p.key )
                        return recSearch( p.left, el );
                else    
                        return recSearch( p.right, el );
        }

        
        /**
         * Traveral methods
         * inOrderVisit
         * preOrderVisit
         * postOrderVisit
         */
        public void inOrderVisit() {
                inOrderVisit( root );
                System.out.println();
        }
        
        private void inOrderVisit( IntBSTNode p ) {
                if ( p==null )
                        return;
                inOrderVisit( p.left );
                System.out.print( p.key + " ");
                inOrderVisit( p.right );
        }
        
        public void preOrderVisit() {
                preOrderVisit( root );
                System.out.println();
        }
        private void preOrderVisit( IntBSTNode p ) {
                if ( p==null )
                        return;
                System.out.print( p.key + " ");
                preOrderVisit( p.left );
                preOrderVisit( p.right );
        }

        public void postOrderVisit() {
                postOrderVisit( root );
                System.out.println();
        }
        private void postOrderVisit( IntBSTNode p ) {
                if ( p==null )
                        return;
                postOrderVisit( p.left );
                postOrderVisit( p.right );
                System.out.print( p.key + " ");
        }

        /**
         * visits the tree breadth-first.  Display the key in all
         * the nodes, in breadth-first order.
         */
        public void breadthFirst() {
                IntBSTNode p = root;
                Queue<IntBSTNode> queue = new LinkedList<IntBSTNode>();
                
                if ( p == null ) 
                        return;
                
                queue.add( p );
                while ( ! queue.isEmpty() ){
                        p = queue.poll();
                        //--- do some work with the key.  Here we just print it...
                        System.out.print( p.key + " " );
                        if ( p.left != null ) queue.add( p.left );
                        if ( p.right != null ) queue.add( p.right );
                }
        }
        
        /**
         * Inserts an element in the tree.  We assume that the element
         * is not already there.
         * @param el
         */
        public void insert( int el ) {          
                // is the tree empty?  if so, create 1 node
                if ( root==null ) {
                        root = new IntBSTNode( el );
                        return;
                }
                
                // go down to the leaf that will be the parent
                // of the new node
                IntBSTNode p = root, prev = null;
                while ( p != null ) {
                        prev = p;
                        if ( p.key < el ) 
                                p = p.right;
                        else
                                p = p.left;
                }
                
                // add element as new leaf of prev's node
                if ( el < prev.key )
                        prev.left = new IntBSTNode( el );
                else
                        prev.right = new IntBSTNode( el );
        }
        
        /**
         * Delete element by merging.  Finds the element, then the largest 
         * of its left-subtree, and attaches the right-subtree of the node to 
         * delete to this largest element.
         * @param el: the key we want to remove.
         */
        public void delete( int el ) { 
                IntBSTNode tmp, node, p=root, prev = null;
                
                if ( root == null ) { 
                        System.out.println( "Trying to delete from an empty tree" );
                        return;
                }
                
                // find the node containing el
                while ( p!=null && p.key != el ) {
                        prev = p;
                        if (p.key < el ) 
                                p = p.right;
                        else
                                p = p.left;
                }
                
                if ( p==null ) {
                        System.out.println( "Key " + el + " not in tree" );
                        return;
                }
                
                // we found the element.  p is pointing to it.  prev is pointing to 
                // parent (or is null if el is in root).
                node = p;
                
                // no right sub-tree?  
                if ( node.right == null ) {
                        // yes, then pick the left subtree
                        node = node.left;
                }
                else if ( node.left == null ) {
                        // yes, then pick the right subtree
                        node = node.right;
                }
                else {
                        // two existing subtrees.
                        // go to left subtree
                        tmp = node.left; 
                        
                        // and find the right-most node that doesn't have a right child.
                        while ( tmp.right != null ) 
                                tmp = tmp.right;
                        
                        // tmp points to right-most node (blue node)
                        
                        // attach right subtree of node we're deleting (yellow node)
                        // to right most node (blue node)
                        tmp.right = node.right;
                        
                        node = node.left;
                }
                
                if ( p==root ) 
                        root = node;
                else if ( prev.left == p )
                        prev.left = node;
                else
                        prev.right = node;
        }
        
        /**
         * balance the tree by copying all the keys into an array first,
         * then sorting the array, then doing some binary split operation,
         * going to the middle of the array to find the root, then to the
         * middle of the two halves to find the children of the root, etc...
         * and rebuilding the tree that way.
         * @return 
         */
        private void addNodeToArray( IntBSTNode p, ArrayList<Integer> allNodes ) {
                if ( p==null ) return;
                addNodeToArray( p.left, allNodes );
                allNodes.add( p.key );
                addNodeToArray( p.right, allNodes );
        }
        
        public void balance() {
                // visit the tree and copy all the nodes into an ArrayList
                // visit in in-order fashion, so as to create a sorted list of keys in the array
                ArrayList<Integer> allNodes = new ArrayList<Integer>();
                addNodeToArray( root, allNodes );
                                
                // recursively reconstruct the tree
                clear();
                recursiveBalance( allNodes, 0, allNodes.size()-1 );
        }
        
        private void recursiveBalance( ArrayList<Integer> allNodes, int low, int high ) {
                if ( low <= high ) {
                        int mid = ( low + high ) / 2;
                        insert( allNodes.get( mid ) );
                        recursiveBalance( allNodes, low, mid-1 );
                        recursiveBalance( allNodes, mid+1, high );
                }
        }

        
        /**
         *                M A I N   P R O G R A M 
         *
        */  
        static public void main( String[] args ) {
                IntBST tree = new IntBST();
                
        // create a new tree by using insert()
        int[] keys = new int[] { 8, 3, 10, 1, 6, 14, 4, 7, 13 };
 
        for ( int i=0; i< keys.length; i++ ) 
                tree.insert( keys[i] ); 
        
        tree.debugVisit();
        }
}