Created
March 23, 2015 07:53
-
-
Save korydondzila/75d5eb5cf3c89ed7ec39 to your computer and use it in GitHub Desktop.
Adavanced Data Structures project to implement a string based AVL tree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* File: prog2.java | |
* Package: None | |
* Project: COMP_282 | |
* Date: Mar 10, 2015, 9:30:11 PM | |
* Purpose: To implement a string AVL tree | |
* @author Kory Dondzila | |
* @version "%I%, %G%" | |
* Copyright: 2015 | |
*/ | |
/** | |
* Node class for a string based AVL tree | |
*/ | |
class StringAVLNode | |
{ | |
/** | |
* The node data | |
*/ | |
private String item; | |
/** | |
* Balance of the node | |
*/ | |
private int balance; | |
/** | |
* Left and right nodes | |
*/ | |
private StringAVLNode left, right; | |
/** | |
* AVLNode constructor | |
* @param str the string to set item to | |
*/ | |
public StringAVLNode(String str) | |
{ | |
this.item = str; | |
balance = 0; | |
left = null; | |
right = null; | |
} | |
/** | |
* @return the balance | |
*/ | |
public int getBalance() | |
{ | |
return this.balance; | |
} | |
/** | |
* @param balance the balance to set | |
*/ | |
public void setBalance( int balance ) | |
{ | |
this.balance = balance; | |
} | |
/** | |
* @return the item | |
*/ | |
public String getItem() | |
{ | |
return this.item; | |
} | |
/** | |
* @return the left | |
*/ | |
public StringAVLNode getLeft() | |
{ | |
return this.left; | |
} | |
/** | |
* @param left the left to set | |
*/ | |
public void setLeft( StringAVLNode left ) | |
{ | |
this.left = left; | |
} | |
/** | |
* @return the right | |
*/ | |
public StringAVLNode getRight() | |
{ | |
return this.right; | |
} | |
/** | |
* @param right the right to set | |
*/ | |
public void setRight( StringAVLNode right ) | |
{ | |
this.right = right; | |
} | |
} | |
/** | |
* The string based AVL tree class | |
*/ | |
class StringAVLTree | |
{ | |
/** | |
* The root node | |
*/ | |
private StringAVLNode root; | |
/** | |
* Default constructor | |
*/ | |
public StringAVLTree() | |
{ | |
root = null; | |
} | |
/** | |
* @return the root | |
*/ | |
public StringAVLNode getRoot() | |
{ | |
return this.root; | |
} | |
/** | |
* Rotate the node to the right | |
* @param t the node to rotate around | |
* @return the rotated node | |
*/ | |
private static StringAVLNode rotateRight( StringAVLNode t ) | |
{ | |
StringAVLNode temp = t.getLeft(); | |
t.setLeft( temp.getRight() ); | |
temp.setRight( t ); | |
return temp; | |
} | |
/** | |
* Rotate the node to the left | |
* @param t the node to rotate around | |
* @return the rotated node | |
*/ | |
private static StringAVLNode rotateLeft( StringAVLNode t ) | |
{ | |
StringAVLNode temp = t.getRight(); | |
t.setRight( temp.getLeft() ); | |
temp.setLeft( t ); | |
return temp; | |
} | |
/** | |
* Double rotation with respect to right child | |
* @param t the node to rotate around | |
* @return the rotated node | |
*/ | |
private static StringAVLNode doubleRotateWithRight( StringAVLNode t ) | |
{ | |
t.setRight( rotateRight( t.getRight() ) ); | |
t = rotateLeft( t ); | |
adjustBalances( t ); // Adjust balances after rotating | |
return t; | |
} | |
/** | |
* Double rotation with respect to left child | |
* @param t the node to rotate around | |
* @return the rotated node | |
*/ | |
private static StringAVLNode doubleRotateWithLeft( StringAVLNode t ) | |
{ | |
t.setLeft( rotateLeft( t.getLeft() ) ); | |
t = rotateRight( t ); | |
adjustBalances( t ); | |
return t; | |
} | |
/** | |
* Adjusts balances for double rotations | |
* @param t the node to adjust balances on | |
*/ | |
private static void adjustBalances( StringAVLNode t ) | |
{ | |
if ( t.getBalance() == 0 ) | |
{ | |
t.getLeft().setBalance( 0 ); | |
t.getRight().setBalance( 0 ); | |
} | |
else if ( t.getBalance() == -1 ) | |
{ | |
t.setBalance( 0 ); | |
t.getLeft().setBalance( 0 ); | |
t.getRight().setBalance( 1 ); | |
} | |
else | |
{ | |
t.setBalance( 0 ); | |
t.getLeft().setBalance( -1 ); | |
t.getRight().setBalance( 0 ); | |
} | |
} | |
/** | |
* Handles rotations and re-balancing after a node deletion | |
* @param t the node to re-balance | |
* @return the re-blanced node | |
*/ | |
private static StringAVLNode deletionRebalance( StringAVLNode t ) | |
{ | |
if ( t.getBalance() == 2 ) // Rotate on the right? | |
{ | |
if ( t.getRight().getBalance() == 1 ) // Single rotate? | |
{ | |
t = rotateLeft( t ); | |
t.setBalance( 0 ); | |
t.getLeft().setBalance( 0 ); | |
} | |
else if ( t.getRight().getBalance() == 0 ) | |
{ | |
t = rotateLeft( t ); | |
t.setBalance( -1 ); | |
t.getLeft().setBalance( 1 ); | |
} | |
else // Double rotate | |
{ | |
t = doubleRotateWithRight( t ); | |
} | |
} | |
else if ( t.getBalance() == -2 ) // Rotate on the left? | |
{ | |
if ( t.getLeft().getBalance() == -1 ) // Single rotate? | |
{ | |
t = rotateRight( t ); | |
t.setBalance( 0 ); | |
t.getRight().setBalance( 0 ); | |
} | |
else if ( t.getLeft().getBalance() == 0 ) // Single rotate? | |
{ | |
t = rotateRight( t ); | |
t.setBalance( 1 ); | |
t.getRight().setBalance( -1 ); | |
} | |
else // Double rotate | |
{ | |
t = doubleRotateWithLeft( t ); | |
} | |
} | |
return t; | |
} | |
/** | |
* Gets height of tree | |
* @return the height | |
*/ | |
public int height() | |
{ | |
return height( root, 0 ); | |
} | |
/** | |
* Recursively finds the height of the tree | |
* @param t the node to get height of | |
* @param count current height | |
* @return current height | |
*/ | |
private static int height( StringAVLNode t, int count ) | |
{ | |
if ( t != null ) | |
{ | |
if ( t.getBalance() <= 0 ) // Go to larger height | |
{ | |
count = height( t.getLeft(), count + 1 ); | |
} | |
else | |
{ | |
count = height( t.getRight(), count + 1 ); | |
} | |
} | |
return count; | |
} | |
/** | |
* Gets the number of leaves | |
* @return the number of leaves | |
*/ | |
public int leafCt() | |
{ | |
return leafCt( root ); | |
} | |
/** | |
* Recursively gets the number of leaves | |
* @param t the node to get leaves on | |
* @return the number of leaves | |
*/ | |
private static int leafCt( StringAVLNode t ) | |
{ | |
int count = 0; | |
if ( t != null ) | |
{ | |
// Increment count on leaf nodes only | |
if ( t.getLeft() == null && t.getRight() == null ) | |
{ | |
count++; | |
} | |
else | |
{ | |
count = leafCt( t.getLeft() ) + leafCt( t.getRight() ); | |
} | |
} | |
return count; | |
} | |
/** | |
* Gets the number of sticks, nodes with only one non-null child | |
* @return the number of sticks | |
*/ | |
public int stickCt() | |
{ | |
return stickCt( root ); | |
} | |
/** | |
* Recursively gets the number of sticks | |
* @param t the node to get sticks on | |
* @return the number of sticks | |
*/ | |
private static int stickCt( StringAVLNode t ) | |
{ | |
int count = 0; | |
if ( t != null ) | |
{ | |
// Increment count only on sticks | |
if ( ( t.getLeft() != null && t.getRight() == null ) || | |
( t.getLeft() == null && t.getRight() != null ) ) | |
{ | |
count++; | |
} | |
else | |
{ | |
count = stickCt( t.getLeft() ) + stickCt( t.getRight() ); | |
} | |
} | |
return count; | |
} | |
/** | |
* Gets the number of perfectly balanced nodes | |
* @return the number of perfectly balanced nodes | |
*/ | |
public int balanced() | |
{ | |
return balanced( root ); | |
} | |
/** | |
* Recursively gets the number of balanced nodes | |
* @param t the node to get balanced nodes on | |
* @return the number of balanced nodes | |
*/ | |
private static int balanced( StringAVLNode t ) | |
{ | |
int count = 0; | |
if ( t != null ) | |
{ | |
if ( t.getBalance() == 0 ) | |
{ | |
count++; | |
} | |
count += balanced( t.getLeft() ) + balanced( t.getRight() ); | |
} | |
return count; | |
} | |
/** | |
* Gets the in-order successor | |
* @param str the string to find in-order successor of | |
* @return the in-order successor or null if there is none or str is not in the tree | |
*/ | |
public String successor( String str ) | |
{ | |
StringAVLNode found = null; | |
String val; | |
found = successor( str, root, null ); | |
val = found != null ? found.getItem() : null; | |
return val; | |
} | |
/** | |
* Recursively finds the in-order successor | |
* @param str the string to find in-order successor of | |
* @param t the current node | |
* @param max the current in-order successor | |
* @return the in-order successor | |
*/ | |
private static StringAVLNode successor( String str, StringAVLNode t, StringAVLNode max ) | |
{ | |
StringAVLNode found = null; | |
if ( t != null ) | |
{ | |
// Recursively look for node containing str only changing max when | |
// going left | |
if ( str != null && str.compareToIgnoreCase( t.getItem() ) < 0 ) | |
{ | |
found = successor( str, t.getLeft(), t ); | |
} | |
else if ( str != null && str.compareToIgnoreCase( t.getItem() ) > 0 ) | |
{ | |
found = successor( str, t.getRight(), max ); | |
} | |
else | |
{ | |
// Once node is found then get its in-order successor | |
if ( str != null /*&& t.getRight() != null*/ ) | |
{ | |
str = null; | |
found = successor( str, t.getRight(), max ); | |
} | |
else | |
{ | |
found = successor( str, t.getLeft(), t ); | |
} | |
} | |
} | |
else if ( str == null ) | |
{ | |
found = max; | |
} | |
return found; | |
} | |
/** | |
* Inserts a new node with str if it doesn't exist | |
* @param str the string to insert | |
*/ | |
public void insert( String str ) | |
{ | |
root = insert( str, root ); | |
} | |
/** | |
* Recursively inserts a new node in the tree | |
* @param str the string to insert | |
* @param t the node to insert to | |
* @return the node t | |
*/ | |
private static StringAVLNode insert( String str, StringAVLNode t ) | |
{ | |
if ( t == null ) // easiest case – inserted node goes here | |
{ | |
t = new StringAVLNode( str ); | |
} | |
else if ( str.compareToIgnoreCase( t.getItem() ) < 0 ) // str is smaller than this node – go left | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on left | |
if ( t.getLeft() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = t.getLeft().getBalance(); | |
} | |
t.setLeft( insert( str, t.getLeft() ) ); // Insert to the left | |
Integer newBalance = t.getLeft().getBalance(); // Get newbalance | |
if ( ( oldBalance == null && newBalance == 0 ) || // Did height increase? | |
( oldBalance == 0 && newBalance != 0 ) ) | |
{ | |
t.setBalance( t.getBalance() - 1 ); // Decrease balance | |
if ( t.getBalance() == -2 ) // out of balance – must rotate and rebalance | |
{ | |
if ( t.getLeft().getBalance() == -1 ) // single rotation | |
{ | |
t = rotateRight( t ); | |
t.setBalance( 0 ); | |
t.getRight().setBalance( 0 ); | |
} | |
else // double rotation | |
{ | |
t = doubleRotateWithLeft( t ); | |
} | |
} | |
} | |
} | |
else if ( str.compareToIgnoreCase( t.getItem() ) > 0 ) // str is larger than this node – go right | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on right | |
if ( t.getRight() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = t.getRight().getBalance(); | |
} | |
t.setRight( insert( str, t.getRight() ) ); // Insert to the right | |
Integer newBalance = t.getRight().getBalance(); // Get newbalance | |
if ( ( oldBalance == null && newBalance == 0 ) || // Did height increase? | |
( oldBalance == 0 && newBalance != 0 ) ) | |
{ | |
t.setBalance( t.getBalance() + 1 ); | |
if ( t.getBalance() == 2 ) // out of balance – must rotate and rebalance | |
{ | |
if ( t.getRight().getBalance() == 1 ) // single rotation | |
{ | |
t = rotateLeft( t ); | |
t.setBalance( 0 ); | |
t.getLeft().setBalance( 0 ); | |
} | |
else // double rotation | |
{ | |
t = doubleRotateWithRight( t ); | |
} | |
} | |
} | |
} | |
return t; | |
} | |
/** | |
* Delete node that contains str if it exists | |
* @param str the string to delete from the tree | |
*/ | |
public void delete( String str ) | |
{ | |
root = delete( str, root ); | |
} | |
/** | |
* Recursively deletes the node from the tree | |
* @param str the string to delete | |
* @param t the current node to delete from | |
* @return the current node | |
*/ | |
private StringAVLNode delete( String str, StringAVLNode t ) | |
{ | |
if ( t == null ) | |
{ | |
// Do nothing if it is not in the tree | |
} | |
else if ( str.compareToIgnoreCase( t.getItem() ) < 0 ) // str is smaller than this node – go left | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on left | |
if ( t.getLeft() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = t.getLeft().getBalance(); | |
} | |
t.setLeft( delete( str, t.getLeft() ) ); // Delete on left | |
Integer newBalance; | |
// Get newbalance if child on left | |
if ( t.getLeft() == null ) | |
{ | |
newBalance = null; | |
} | |
else | |
{ | |
newBalance = t.getLeft().getBalance(); | |
} | |
if ( oldBalance != null && // Did node exist and did height decrease? | |
( ( oldBalance == 0 && newBalance == null ) || | |
( oldBalance != 0 && newBalance == 0 ) ) ) | |
{ | |
t.setBalance( t.getBalance() + 1 ); // Increase balance then possibly rotate | |
t = deletionRebalance( t ); | |
} | |
} | |
else if ( str.compareToIgnoreCase( t.getItem() ) > 0 ) // str is larger than this node – go right | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on right | |
if ( t.getRight() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = t.getRight().getBalance(); | |
} | |
t.setRight( delete( str, t.getRight() ) ); // Delete on right | |
Integer newBalance; | |
// Get newbalance if child on right | |
if ( t.getRight() == null ) | |
{ | |
newBalance = null; | |
} | |
else | |
{ | |
newBalance = t.getRight().getBalance(); | |
} | |
if ( oldBalance != null && // Did node exist and did height decrease? | |
( ( oldBalance == 0 && newBalance == null ) || | |
( oldBalance != 0 && newBalance == 0 ) ) ) | |
{ | |
t.setBalance( t.getBalance() - 1 ); // Decrease balance and possibly rotate | |
t = deletionRebalance( t ); | |
} | |
} | |
else // Node to be deleted | |
{ | |
if ( t.getLeft() == null && t.getRight() == null ) // no children, remove | |
{ | |
t = null; | |
} | |
else if ( t.getLeft() == null || t.getRight() == null ) // one child, replace | |
{ | |
t = t.getLeft() != null ? t.getLeft() : t.getRight(); | |
} | |
else // Two children | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on left | |
if ( t.getLeft() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = t.getLeft().getBalance(); | |
} | |
t = replace( t, null, t.getLeft() ); // Replace with in-order predecessor | |
Integer newBalance; | |
// Get newbalance if child on left | |
if ( t.getLeft() == null ) | |
{ | |
newBalance = null; | |
} | |
else | |
{ | |
newBalance = t.getLeft().getBalance(); | |
} | |
if ( oldBalance != null && // Did node exist and did height decrease? | |
( ( oldBalance == 0 && newBalance == null ) || | |
( oldBalance != 0 && newBalance == 0 ) ) ) | |
{ | |
t.setBalance( t.getBalance() + 1 ); // Increase balance and possibly rotate | |
t = deletionRebalance( t ); | |
} | |
} | |
} | |
return t; | |
} | |
/** | |
* Recursively replaces node t with its in-order predecessor | |
* @param t the node to delete | |
* @param prev the previous current node | |
* @param replacement the current node to replace t with | |
* @return the current node | |
*/ | |
private StringAVLNode replace( StringAVLNode t, StringAVLNode prev, StringAVLNode replacement ) | |
{ | |
if ( replacement.getRight() == null ) // at in-order predecessor | |
{ | |
StringAVLNode temp = null; | |
if ( prev != null ) // if replacement node is NOT the child | |
{ | |
temp = replacement.getLeft(); // will become prev's right | |
} | |
else | |
{ | |
temp = replacement.getLeft(); | |
} | |
// Replacing t | |
replacement.setRight( t.getRight() ); // attach t's right | |
replacement.setBalance( t.getBalance() ); // need to have t's balance | |
t = replacement; // replace t | |
replacement = temp; | |
} | |
else // Not yet at in-order predecessor | |
{ | |
Integer oldBalance; | |
// Get oldbalance if child on right | |
if ( replacement.getRight() == null ) | |
{ | |
oldBalance = null; | |
} | |
else | |
{ | |
oldBalance = replacement.getRight().getBalance(); | |
} | |
t = replace( t, replacement, replacement.getRight() ); // replace with in-order predecessor | |
Integer newBalance; | |
// Get newbalance if child on right | |
if ( replacement.getRight() == null ) | |
{ | |
newBalance = null; | |
} | |
else | |
{ | |
newBalance = replacement.getRight().getBalance(); | |
} | |
if ( oldBalance != null && // Did node exist and did height decrease? | |
( ( oldBalance == 0 && newBalance == null ) || | |
( oldBalance != 0 && newBalance == 0 ) ) ) | |
{ | |
// Decrease balance and possibly rotate | |
replacement.setBalance( replacement.getBalance() - 1 ); | |
replacement = deletionRebalance( replacement ); | |
} | |
} | |
// Properly re-attach nodes back up tree, since t is returned | |
// this must get done in the case where a rotation happened | |
if ( prev != null ) // Not yet at top recursive call so set prev's right | |
{ | |
prev.setRight( replacement ); | |
} | |
else // At top recursive call, set t's left | |
{ | |
t.setLeft( replacement ); | |
} | |
return t; | |
} | |
/** | |
* @return the author | |
*/ | |
public static String myName() | |
{ | |
return "Kory A. Dondzila"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment