Last active
March 6, 2018 16:32
-
-
Save kmalcaba/735b4f21785b0042aa7d0cf9eb084fd7 to your computer and use it in GitHub Desktop.
AVL Balancing Tree written in Java, part of a machine problem in Algorithms class.
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
package machineproblem3; | |
import java.awt.FlowLayout; | |
import java.awt.GridLayout; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.util.ArrayList; | |
import java.util.InputMismatchException; | |
import javax.swing.JButton; | |
import javax.swing.JOptionPane; | |
import javax.swing.JPanel; | |
import javax.swing.JTextField; | |
import javax.swing.SwingUtilities; | |
/** | |
* | |
* @author kamalcaba | |
*/ | |
public class AVLPanel extends JPanel implements ActionListener { | |
//container of the heap sorted number list | |
ArrayList<Integer> numberList; | |
AVLTree tree; | |
JPanel buttonPanel; | |
JButton insertButton; | |
JButton clearButton; | |
JTextField insertField; | |
public AVLPanel() { | |
setLayout(new FlowLayout()); | |
numberList = new ArrayList(); | |
tree = new AVLTree(); | |
buttonPanel = new JPanel(); | |
insertButton = new JButton("Insert"); | |
clearButton = new JButton("Clear"); | |
insertField = new JTextField(); | |
buttonPanel.setLayout(new GridLayout(3, 1)); | |
insertButton.addActionListener(this); | |
clearButton.addActionListener(this); | |
insertField.setHorizontalAlignment(JTextField.CENTER); | |
buttonPanel.add(insertField); | |
buttonPanel.add(insertButton); | |
buttonPanel.add(clearButton); | |
add(tree); | |
add(buttonPanel); | |
setVisible(true); | |
} | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
try { | |
//If inserting a node | |
if (e.getSource() == insertButton) { | |
if (!numberList.isEmpty()) { | |
tree.treeArea.setText(""); | |
for (Integer num : numberList) { | |
tree.count = 0; | |
tree.root = tree.insertNode(tree.root, num); | |
tree.printNode(tree.root); | |
tree.treeArea.append(num + " inserted\n\n"); | |
} | |
} | |
//Check if the text field is empty or contains letters/symbols | |
//If true, throw exception | |
if (numberList.isEmpty()) { | |
String insertFieldText = insertField.getText().trim(); | |
if (insertFieldText.isEmpty() && numberList.isEmpty()) { | |
throw new InputMismatchException("Text field cannot be empty!"); | |
} else if (Character.isAlphabetic(insertFieldText.charAt(0))) { | |
throw new InputMismatchException("Numbers only!"); | |
} | |
int insertKey = Integer.parseInt(insertFieldText); | |
tree.count = 0; | |
tree.root = tree.insertNode(tree.root, insertKey); | |
tree.printNode(tree.root); | |
tree.treeArea.append(insertKey + " inserted\n\n"); | |
tree.treeArea.append("--------------------------\n\n"); | |
System.out.println(insertKey + " inserted\n"); | |
System.out.println("--------------------------\n"); | |
} | |
if (!numberList.isEmpty()) { | |
numberList.removeAll(numberList); | |
} | |
insertField.setText(""); | |
} | |
else if (e.getSource() == clearButton) { | |
tree.treeArea.setText(""); | |
} | |
} catch (InputMismatchException | NumberFormatException ex) { | |
JOptionPane.showMessageDialog(SwingUtilities.getRootPane(this), ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); | |
} | |
} | |
} |
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
package machineproblem3; | |
import java.awt.FlowLayout; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import javax.swing.JPanel; | |
import javax.swing.JScrollPane; | |
import javax.swing.JTextArea; | |
/** | |
* | |
* @author kamalcaba | |
*/ | |
class Node { | |
public int key; | |
public int height; | |
public Node left; | |
public Node right; | |
Node(int value) { | |
key = value; | |
height = 1; | |
} | |
Node() { | |
left = right = null; | |
} | |
} | |
public class AVLTree extends JPanel { | |
JTextArea treeArea; | |
JScrollPane treeScroll; | |
Node root; | |
int count; | |
public AVLTree() { | |
setLayout(new FlowLayout()); | |
count = 0; | |
treeArea = new JTextArea(28, 30); | |
treeArea.setEditable(false); | |
treeArea.setLineWrap(true); | |
treeScroll = new JScrollPane(treeArea); | |
treeScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); | |
add(treeScroll); | |
setVisible(true); | |
} | |
//Returns the height of the tree | |
int height(Node N) { | |
if (N == null) { | |
return 0; | |
} | |
return N.height; | |
} | |
Node rightRotate(Node N) { | |
Node left = N.left; | |
Node right = left.right; | |
//Perform rotation | |
left.right = N; | |
N.left = right; | |
//Update heights | |
N.height = Integer.max(height(N.left), height(N.right)) + 1; | |
left.height = Integer.max(height(left.left), height(left.right)) + 1; | |
//Return new root | |
return left; | |
} | |
Node leftRotate(Node N) { | |
Node right = N.right; | |
Node left = right.left; | |
//Perform rotation | |
right.left = N; | |
N.right = left; | |
//Update heights | |
N.height = Integer.max(height(N.left), height(N.right)) + 1; | |
right.height = Integer.max(height(right.left), height(right.right)) + 1; | |
//Return new root | |
return right; | |
} | |
//Returns the balance of the tree | |
int getBalance(Node N) { | |
if (N == null) { | |
return 0; | |
} | |
return height(N.left) - height(N.right); | |
} | |
Node insertNode(Node root, int key) { | |
//Perform BST insertion | |
if (root == null) { | |
return (new Node(key)); | |
} | |
//If key is lesser than the root, | |
//insert to the left subtree | |
if (key < root.key) { | |
root.left = insertNode(root.left, key); | |
} //If key is greater than the root, | |
//insert to the right subtree | |
else if (key > root.key) { | |
root.right = insertNode(root.right, key); | |
} //If key already exists, ignore | |
else { | |
return root; | |
} | |
//Update heights | |
root.height = Integer.max(height(root.left), height(root.right)) + 1; | |
//Get the balance of the tree | |
int balance = getBalance(root); | |
//Print every rotation of the tree | |
if (count > 0) { | |
if (balance > 1 || balance < -1) { | |
printNode(root); | |
} | |
} | |
count++; | |
//If the tree is unbalanced, | |
//there are 4 types of rotation | |
//Single Right Rotation | |
if (balance > 1 && key < root.left.key) { | |
System.out.println("Right rotation\n"); | |
treeArea.append("Right rotation\n\n"); | |
return rightRotate(root); | |
} | |
//Single Left Rotation | |
if (balance < -1 && key > root.right.key) { | |
System.out.println("Left rotation\n"); | |
treeArea.append("Left rotation\n\n"); | |
return leftRotate(root); | |
} | |
//Double Left Right Rotation | |
if (balance > 1 && key > root.left.key) { | |
root.left = leftRotate(root.left); | |
System.out.println("Left Right rotation\n"); | |
treeArea.append("Left Right rotation\n\n"); | |
return rightRotate(root); | |
} | |
//Double Right Left Rotation | |
if (balance < -1 && key < root.right.key) { | |
root.right = rightRotate(root.right); | |
System.out.println("Right Left rotation\n"); | |
treeArea.append("Right Left rotation\n\n"); | |
return leftRotate(root); | |
} | |
return root; | |
} | |
//The following functions are used to print the tree: | |
//Prints the tree from the root of a (sub)tree | |
public void printNode(Node root) { | |
int maxLevel = maxLevel(root); | |
printInternalNodes(Collections.singletonList(root), 1, maxLevel); | |
} | |
private void printInternalNodes(List<Node> nodes, int level, int maxLevel) { | |
//Base case | |
if (nodes.isEmpty() || isAllElementsNull(nodes)) { | |
return; | |
} | |
//Computing the number of whitespaces in between | |
int floor = maxLevel - level; | |
int edges = (int) Math.pow(2, (Math.max(floor - 1, 0))); | |
int firstSpaces = (int) Math.pow(2, (floor)) - 1; | |
int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1; | |
printWhitespaces(firstSpaces); | |
List<Node> newNodes = new ArrayList<>(); | |
for (Node node : nodes) { | |
if (node != null) { | |
//Print the key | |
treeArea.append(" " + String.valueOf(node.key) + " "); | |
System.out.print(node.key); | |
newNodes.add(node.left); | |
newNodes.add(node.right); | |
} else { | |
newNodes.add(null); | |
newNodes.add(null); | |
treeArea.append(" "); | |
System.out.print(" "); | |
} | |
printWhitespaces(betweenSpaces); | |
} | |
System.out.println(""); | |
treeArea.append("\n"); | |
//Printing the branches of the tree | |
for (int i = 1; i <= edges; i++) { | |
for (int j = 0; j < nodes.size(); j++) { | |
printWhitespaces(firstSpaces - i); | |
if (nodes.get(j) == null) { | |
printWhitespaces(edges + edges + i + 1); | |
continue; | |
} | |
if (nodes.get(j).left != null) { | |
treeArea.append(" / "); | |
System.out.print("/"); | |
} else { | |
printWhitespaces(1); | |
} | |
printWhitespaces(i + i - 1); | |
if (nodes.get(j).right != null) { | |
treeArea.append(" \\ "); | |
System.out.print(" \\"); | |
} else { | |
printWhitespaces(1); | |
} | |
printWhitespaces(edges + edges - i); | |
} | |
treeArea.append("\n"); | |
System.out.println(""); | |
} | |
printInternalNodes(newNodes, level + 1, maxLevel); | |
} | |
private void printWhitespaces(int count) { | |
for (int i = 0; i < count; i++) { | |
treeArea.append(" "); | |
System.out.print(" "); | |
} | |
} | |
//Determines the highest level between the left and right subtrees | |
private int maxLevel(Node node) { | |
if (node == null) { | |
return 0; | |
} | |
return Math.max(maxLevel(node.left), maxLevel(node.right)) + 1; | |
} | |
private boolean isAllElementsNull(List list) { | |
for (Object object : list) { | |
if (object != null) { | |
return false; | |
} | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment