Difference between revisions of "CSC212 IntBST.java: A Non-Generic BST Implementation"
(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.Queue; | import java.util.Queue; | ||
Line 24: | Line 23: | ||
*/ | */ | ||
class IntBSTNode { | 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 ); | |
− | + | } | |
} | } | ||
Line 44: | Line 43: | ||
*/ | */ | ||
public class IntBST { | 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() | // 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.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();
}
}