Skip to content

Instantly share code, notes, and snippets.

@kmalcaba
Last active March 6, 2018 16:32
Show Gist options
  • Save kmalcaba/735b4f21785b0042aa7d0cf9eb084fd7 to your computer and use it in GitHub Desktop.
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.
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);
}
}
}
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