Difference between revisions of "CSC212 IntBST.java: A Non-Generic BST Implementation"

From dftwiki3
Jump to: navigation, search
 
(3 intermediate revisions by the same user not shown)
Line 14: Line 14:
 
import java.util.Collections;
 
import java.util.Collections;
 
import java.util.LinkedList;
 
import java.util.LinkedList;
import java.util.List;
 
 
import java.util.Queue;
 
import java.util.Queue;
  
Line 24: Line 23:
 
  */
 
  */
 
class IntBSTNode {
 
class IntBSTNode {
+
       
public int key;
+
        public int key;
public IntBSTNode left, right;
+
        public IntBSTNode left, right;
IntBSTNode( int el, IntBSTNode l, IntBSTNode r ) {
+
        IntBSTNode( int el, IntBSTNode l, IntBSTNode r ) {
key = el;
+
                key = el;
left = l;
+
                left = l;
right = r;
+
                right = r;
}
+
        }
+
       
IntBSTNode( int el ) {
+
        IntBSTNode( int el ) {
this( el, null, null );
+
                this( el, null, null );
}
+
        }
 
}
 
}
  
Line 44: Line 43:
 
  */
 
  */
 
public class IntBST {
 
public class IntBST {
protected IntBSTNode root;
+
        protected IntBSTNode root;
+
       
/**
+
        /**
* constructor creates an empty tree.
+
        * constructor creates an empty tree.
*/
+
        */
IntBST( ) {
+
        IntBST( ) {
root = null;
+
                root = null;
}
+
        }
+
       
protected void setRoot( IntBSTNode p ) {  
+
        protected void setRoot( IntBSTNode p ) {  
root = p;  
+
                root = p;  
}
+
        }
+
       
public void clear() {
+
        public void clear() {
root = null;
+
                root = null;
}
+
        }
+
       
/**
+
        /**
* Just use for debugging...  Recursively visits the tree
+
        * Just use for debugging...  Recursively visits the tree
* and display information about what it finds.
+
        * and display information about what it finds.
*/
+
        */
protected void debugVisit() {
+
        protected void debugVisit() {
debugVisit( root );
+
                debugVisit( root );
}
+
        }
+
               
protected void debugVisit( IntBSTNode p ) {  
+
        protected void debugVisit( IntBSTNode p ) {  
if ( p==null ) return;
+
                if ( p==null ) return;
String leftString="has no left child", rightString = "has no right child";
+
                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.left != null) leftString = "has " + p.left.key + " as left child";
if ( p.right != null) rightString = "has " + p.right.key + " as right child";
+
                if ( p.right != null) rightString = "has " + p.right.key + " as right child";
System.out.println( "Node " + p.key + ", " + leftString + ", and " + rightString );
+
                System.out.println( "Node " + p.key + ", " + leftString + ", and " + rightString );
debugVisit( p.left );
+
                debugVisit( p.left );
debugVisit( p.right );
+
                debugVisit( p.right );
}
+
        }
+
       
/**
+
        /**
* Iteratively searches for an element in the tree.  Returns the node
+
        * Iteratively searches for an element in the tree.  Returns the node
* containing the element if found, or null otherwise.
+
        * containing the element if found, or null otherwise.
* @param el
+
        * @param el
* @return
+
        * @return
*/
+
        */
public IntBSTNode search( int el ) {  
+
        public IntBSTNode search( int el ) {  
IntBSTNode p = root;
+
                IntBSTNode p = root;
while ( p != null ) {
+
                while ( p != null ) {
if ( el == p.key )  
+
                        if ( el == p.key )  
return p;
+
                                return p;
if ( el < p.key )
+
                        if ( el < p.key )
p = p.left;
+
                                p = p.left;
else  
+
                        else  
p = p.right;
+
                                p = p.right;
}
+
                }
return null;
+
                return null;          
}
+
        }
  
/**
+
        /**
* recursively searches for an element in the tree.  Returns the
+
        * recursively searches for an element in the tree.  Returns the
* node containing the element, or null if not found.
+
        * node containing the element, or null if not found.
* @param el
+
        * @param el
* @return
+
        * @return
*/
+
        */
public IntBSTNode recSearch( int el ) {  
+
        public IntBSTNode recSearch( int el ) {  
return recSearch( root, el );
+
                return recSearch( root, el );
}
+
        }
+
       
private IntBSTNode recSearch( IntBSTNode p, int el ) {  
+
        private IntBSTNode recSearch( IntBSTNode p, int el ) {  
if ( p==null )
+
                if ( p==null )
return null;
+
                        return null;
if ( el == p.key )  
+
                if ( el == p.key )  
return p;
+
                        return p;
if ( el < p.key )
+
                if ( el < p.key )
return recSearch( p.left, el );
+
                        return recSearch( p.left, el );
else
+
                else  
return recSearch( p.right, el );
+
                        return recSearch( p.right, el );
}
+
        }
  
+
       
/**
+
        /**
* Traveral methods
+
        * Traveral methods
* inOrderVisit
+
        * inOrderVisit
* preOrderVisit
+
        * preOrderVisit
* postOrderVisit
+
        * postOrderVisit
*/
+
        */
public void inOrderVisit() {
+
        public void inOrderVisit() {
inOrderVisit( root );
+
                inOrderVisit( root );
System.out.println();
+
                System.out.println();
}
+
        }
+
       
private void inOrderVisit( IntBSTNode p ) {
+
        private void inOrderVisit( IntBSTNode p ) {
if ( p==null )
+
                if ( p==null )
return;
+
                        return;
inOrderVisit( p.left );
+
                inOrderVisit( p.left );
System.out.print( p.key + " ");
+
                System.out.print( p.key + " ");
inOrderVisit( p.right );
+
                inOrderVisit( p.right );
}
+
        }
+
       
public void preOrderVisit() {
+
        public void preOrderVisit() {
preOrderVisit( root );
+
                preOrderVisit( root );
System.out.println();
+
                System.out.println();
}
+
        }
private void preOrderVisit( IntBSTNode p ) {
+
        private void preOrderVisit( IntBSTNode p ) {
if ( p==null )
+
                if ( p==null )
return;
+
                        return;
System.out.print( p.key + " ");
+
                System.out.print( p.key + " ");
preOrderVisit( p.left );
+
                preOrderVisit( p.left );
preOrderVisit( p.right );
+
                preOrderVisit( p.right );
}
+
        }
  
public void postOrderVisit() {
+
        public void postOrderVisit() {
postOrderVisit( root );
+
                postOrderVisit( root );
System.out.println();
+
                System.out.println();
}
+
        }
private void postOrderVisit( IntBSTNode p ) {
+
        private void postOrderVisit( IntBSTNode p ) {
if ( p==null )
+
                if ( p==null )
return;
+
                        return;
postOrderVisit( p.left );
+
                postOrderVisit( p.left );
postOrderVisit( p.right );
+
                postOrderVisit( p.right );
System.out.print( p.key + " ");
+
                System.out.print( p.key + " ");
}
+
        }
  
/**
+
        /**
* visits the tree breadth-first.  Display the key in all
+
        * visits the tree breadth-first.  Display the key in all
* the nodes, in breadth-first order.
+
        * the nodes, in breadth-first order.
*/
+
        */
public void breadthFirst() {
+
        public void breadthFirst() {
IntBSTNode p = root;
+
                IntBSTNode p = root;
Queue<IntBSTNode> queue = new LinkedList<IntBSTNode>();
+
                Queue<IntBSTNode> queue = new LinkedList<IntBSTNode>();
+
               
if ( p == null )  
+
                if ( p == null )  
return;
+
                        return;
+
               
queue.add( p );
+
                queue.add( p );
while ( ! queue.isEmpty() ){
+
                while ( ! queue.isEmpty() ){
p = queue.poll();
+
                        p = queue.poll();
//--- do some work with the key.  Here we just print it...
+
                        //--- do some work with the key.  Here we just print it...
System.out.print( p.key + " " );
+
                        System.out.print( p.key + " " );
if ( p.left != null ) queue.add( p.left );
+
                        if ( p.left != null ) queue.add( p.left );
if ( p.right != null ) queue.add( p.right );
+
                        if ( p.right != null ) queue.add( p.right );
}
+
                }
}
+
        }
+
       
/**
+
        /**
* Inserts an element in the tree.  We assume that the element
+
        * Inserts an element in the tree.  We assume that the element
* is not already there.
+
        * is not already there.
* @param el
+
        * @param el
*/
+
        */
public void insert( int el ) {
+
        public void insert( int el ) {        
// is the tree empty?  if so, create 1 node
+
                // is the tree empty?  if so, create 1 node
if ( root==null ) {
+
                if ( root==null ) {
root = new IntBSTNode( el );
+
                        root = new IntBSTNode( el );
return;
+
                        return;
}
+
                }
+
               
// go down to the leaf that will be the parent
+
                // go down to the leaf that will be the parent
// of the new node
+
                // of the new node
IntBSTNode p = root, prev = null;
+
                IntBSTNode p = root, prev = null;
while ( p != null ) {
+
                while ( p != null ) {
prev = p;
+
                        prev = p;
if ( p.key < el )  
+
                        if ( p.key < el )  
p = p.right;
+
                                p = p.right;
else
+
                        else
p = p.left;
+
                                p = p.left;
}
+
                }
+
               
// add element as new leaf of prev's node
+
                // add element as new leaf of prev's node
if ( el < prev.key )
+
                if ( el < prev.key )
prev.left = new IntBSTNode( el );
+
                        prev.left = new IntBSTNode( el );
else
+
                else
prev.right = new IntBSTNode( el );
+
                        prev.right = new IntBSTNode( el );
}
+
        }
+
       
/**
+
        /**
* Delete element by merging.  Finds the element, then the largest  
+
        * Delete element by merging.  Finds the element, then the largest  
* of its left-subtree, and attaches the right-subtree of the node to  
+
        * of its left-subtree, and attaches the right-subtree of the node to  
* delete to this largest element.
+
        * delete to this largest element.
* @param el: the key we want to remove.
+
        * @param el: the key we want to remove.
*/
+
        */
public void delete( int el ) {  
+
        public void delete( int el ) {  
IntBSTNode tmp, node, p=root, prev = null;
+
                IntBSTNode tmp, node, p=root, prev = null;
+
               
if ( root == null ) {  
+
                if ( root == null ) {  
System.out.println( "Trying to delete from an empty tree" );
+
                        System.out.println( "Trying to delete from an empty tree" );
return;
+
                        return;
}
+
                }
+
               
// find the node containing el
+
                // find the node containing el
while ( p!=null && p.key != el ) {
+
                while ( p!=null && p.key != el ) {
prev = p;
+
                        prev = p;
if (p.key < el )  
+
                        if (p.key < el )  
p = p.right;
+
                                p = p.right;
else
+
                        else
p = p.left;
+
                                p = p.left;
}
+
                }
+
               
if ( p==null ) {
+
                if ( p==null ) {
System.out.println( "Key " + el + " not in tree" );
+
                        System.out.println( "Key " + el + " not in tree" );
return;
+
                        return;
}
+
                }
+
               
// we found the element.  p is pointing to it.  prev is pointing to  
+
                // we found the element.  p is pointing to it.  prev is pointing to  
// parent (or is null if el is in root).
+
                // parent (or is null if el is in root).
node = p;
+
                node = p;
+
               
// no right sub-tree?   
+
                // no right sub-tree?   
if ( node.right == null ) {
+
                if ( node.right == null ) {
// yes, then pick the left subtree
+
                        // yes, then pick the left subtree
node = node.left;
+
                        node = node.left;
}
+
                }
else if ( node.left == null ) {
+
                else if ( node.left == null ) {
// yes, then pick the right subtree
+
                        // yes, then pick the right subtree
node = node.right;
+
                        node = node.right;
}
+
                }
else {
+
                else {
// two existing subtrees.
+
                        // two existing subtrees.
// go to left subtree
+
                        // go to left subtree
tmp = node.left;  
+
                        tmp = node.left;  
+
                       
// and find the right-most node that doesn't have a right child.
+
                        // and find the right-most node that doesn't have a right child.
while ( tmp.right != null )  
+
                        while ( tmp.right != null )  
tmp = tmp.right;
+
                                tmp = tmp.right;
+
                       
// tmp points to right-most node (blue node)
+
                        // tmp points to right-most node (blue node)
+
                       
// attach right subtree of node we're deleting (yellow node)
+
                        // attach right subtree of node we're deleting (yellow node)
// to right most node (blue node)
+
                        // to right most node (blue node)
tmp.right = node.right;
+
                        tmp.right = node.right;
+
                       
node = node.left;
+
                        node = node.left;
}
+
                }
+
               
if ( p==root )  
+
                if ( p==root )  
root = node;
+
                        root = node;
else if ( prev.left == p )
+
                else if ( prev.left == p )
prev.left = node;
+
                        prev.left = node;
else
+
                else
prev.right = node;
+
                        prev.right = node;
}
+
        }
+
       
/**
+
        /**
* balance the tree by copying all the keys into an array first,
+
        * balance the tree by copying all the keys into an array first,
* then sorting the array, then doing some binary split operation,
+
        * then sorting the array, then doing some binary split operation,
* going to the middle of the array to find the root, then to the
+
        * 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...
+
        * middle of the two halves to find the children of the root, etc...
* and rebuilding the tree that way.
+
        * and rebuilding the tree that way.
* @return  
+
        * @return  
*/
+
        */
private void addNodeToArray( IntBSTNode p, ArrayList allNodes ) {
+
        private void addNodeToArray( IntBSTNode p, ArrayList<Integer> allNodes ) {
if ( p==null ) return;
+
                if ( p==null ) return;
allNodes.add( p.key );
+
                addNodeToArray( p.left, allNodes );
addNodeToArray( p.left, allNodes );
+
                allNodes.add( p.key );
addNodeToArray( p.right, allNodes );
+
                addNodeToArray( p.right, allNodes );
}
+
        }
+
       
public void balance() {
+
        public void balance() {
// visit the tree and copy all the nodes into an ArrayList
+
                // visit the tree and copy all the nodes into an ArrayList
ArrayList allNodes = new ArrayList();
+
                // visit in in-order fashion, so as to create a sorted list of keys in the array
addNodeToArray( root, allNodes );
+
                ArrayList<Integer> allNodes = new ArrayList<Integer>();
+
                addNodeToArray( root, allNodes );
// sort the ArrayList
+
                               
Collections.sort( allNodes );
+
                // recursively reconstruct the tree
+
                clear();
// recursively reconstruct the tree
+
                recursiveBalance( allNodes, 0, allNodes.size()-1 );
clear();
+
        }
recursiveBalance( allNodes, 0, allNodes.size()-1 );
+
       
}
+
        private void recursiveBalance( ArrayList<Integer> allNodes, int low, int high ) {
+
                if ( low <= high ) {
private void recursiveBalance( ArrayList allNodes, int low, int high ) {
+
                        int mid = ( low + high ) / 2;
if ( low <= high ) {
+
                        insert( allNodes.get( mid ) );
int mid = ( low + high ) / 2;
+
                        recursiveBalance( allNodes, low, mid-1 );
insert( (int) allNodes.get( mid ) );
+
                        recursiveBalance( allNodes, mid+1, high );
recursiveBalance( allNodes, low, mid-1 );
+
                }
recursiveBalance( allNodes, mid+1, high );
+
        }
}
 
}
 
  
+
       
/**
+
        /**
*                M A I N  P R O G R A M  
+
        *                M A I N  P R O G R A M  
*
+
        *
*/   
+
        */   
static public void main( String[] args ) {
+
        static public void main( String[] args ) {
IntBST2 tree = new IntBST2();
+
                IntBST tree = new IntBST();
+
               
 
         // create a new tree by using insert()
 
         // create a new tree by using insert()
 
         int[] keys = new int[] { 8, 3, 10, 1, 6, 14, 4, 7, 13 };
 
         int[] keys = new int[] { 8, 3, 10, 1, 6, 14, 4, 7, 13 };
 
   
 
   
 
         for ( int i=0; i< keys.length; i++ )  
 
         for ( int i=0; i< keys.length; i++ )  
        tree.insert( keys[i] );
+
                tree.insert( keys[i] );  
 
          
 
          
 
         tree.debugVisit();
 
         tree.debugVisit();
}
+
        }
 
}
 
}
 +
  
  

Latest revision as of 13:48, 30 October 2014

--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();
        }
}