if(t == null) //If search is complete and no element is found
{
return null;
}
else
{
if(x < t.data)
t.left = delete(t.left, x);
else if(x > t.data)
t.right = delete(t.right, x);
else if(t.left != null && t.right != null)
{
TreeNode temp = findMax(t.left);
t.data = temp.data;
t.left = delete(t.left, temp.data);
}
else
{
TreeNode child = null;
if(t.left == null)
child = t.right;
if(t.right == null)
child = t.left;
return child;
}
t.height = Math.max(height(t.left), height(t.right)) + 1; //Update the height of TreeNodes
t = balanceTree(t);
return t;
}
private TreeNode balanceTree(TreeNode t)
{
if(getBalance(t) > 1)
{
if (getBalance(t.left) >= 0)
return singleRotateLeftToRight(t);
else
return doubleRotateLeftToRight(t);
}
else
{
if (getBalance(t) < -1)
{
if (getBalance(t.right) <= 0)
return singleRotateRightToLeft(t);
else
return doubleRotateRightToLeft(t);
}
}
return t;
}
public static void main(String[] args)
{
AVLTree v = new AVLTree();
v.insert(50);
v.insert(40);
v.insert(35);
v.insert(37);
v.insert(34);
v.insert(55);
v.insert(60);
v.insert(54);
v.insert(53);
v.insert(52);
v.insert(5);
v.insert(4);
v.insert(3);
v.delete(40);
v.delete(35);
v.delete(37);
v.delete(53);
v.delete(60);
v.insert(2);
v.insert(6);
v.delete(34);
v.delete(6);
v.delete(50);
v.delete(4);
v.delete(3);
v.delete(2);
}
private TreeNode singleRotateLeftToRight(TreeNode k1) // (Utility Method) Performs single rotation of a TreeNode from left to right
{
TreeNode k2 = k1.left;
k1.left = k2.right;
k2.right = k1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
return k2;
}
private TreeNode singleRotateRightToLeft(TreeNode k1) //(Utility Method) Performs single rotation of a TreeNode from right to left
{
TreeNode k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
return k2;
}
private TreeNode doubleRotateLeftToRight(TreeNode k1) //(Utility Method) Performs double rotation of a TreeNode from left to right
{
k1.left = singleRotateRightToLeft(k1.left);
return singleRotateLeftToRight(k1);
}
private TreeNode doubleRotateRightToLeft(TreeNode k1) //(Utility Method) Performs double rotation of a TreeNode from right to left
{
k1.right = singleRotateLeftToRight(k1.right);
return singleRotateRightToLeft(k1);
}
private int getBalance(TreeNode t) { //Returns the difference between the height of the left TreeNode and right TreeNode (utility method)
if(t == null)
return -1;
return height(t.left) - height(t.right);
}
the insertion code works fine but when it comes to deletion I get problems its like some tree nodes disappear and I'm sure that the rotation codes are fine but whats wrong with my code when I delete the tree node with 2 the nodes with 54 and 55 are missing and I'm pretty sure there are no problems with the deletion but it should be with the rotations or maybe I'm balancing the wrong nodes I don't know.
Related
I'm trying to find Minimum path sum from root to leaf also need to compute the minimum path. My solution works if the solution is in left sub tree, however if the result is in right subtree root node is added twice in the result path, can someone please take a look at my solution and help me fixing this bug, also suggest better runtime solution if there is any
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import static java.lang.System.out;
public class MinPathSumFromRootToLeaf {
public static void main(String[] args) {
TreeNode root = new TreeNode(-1);
TreeNode left1 = new TreeNode(2);
TreeNode right1 = new TreeNode(1);//3
TreeNode left2 = new TreeNode(4);
root.left = left1;
root.right = right1;
left1.left = left2;
TreeNode left3 = new TreeNode(0);//5
TreeNode right3 = new TreeNode(1);//6
right1.left = left3;
right1.right = right3;
left3.left = new TreeNode(0);//7
right3.left = new TreeNode(8);
right3.right = new TreeNode(1);//9
printLevelOrder(root);
shortestPathFromRootToLeaf(root);
}
private static void shortestPathFromRootToLeaf(TreeNode root) {
List<Integer> result = new ArrayList<>();
int minsum[] = new int[1];
minsum[0] = Integer.MAX_VALUE;
backtrack(root, result, new ArrayList<>(), 0, minsum);
out.println(result + " minsum " + minsum[0]);
}
private static void backtrack(TreeNode node, List<Integer> result, List<Integer> currentpath, int currentSum, int[] minsum) {
if (node == null || currentSum > minsum[0]) {
return;
}
if (node.left == null && node.right == null) {
if (currentSum + node.val < minsum[0]) {
minsum[0] = currentSum + node.val;
currentpath.add(node.val);
result.clear();
result.addAll(new ArrayList<>(currentpath));
return;
}
}
if (node.left != null) {
currentpath.add(node.val);
backtrack(node.left, result, currentpath, currentSum + node.val, minsum);
currentpath.remove(currentpath.size() - 1);
}
if (node.right != null) {
currentpath.add(node.val);
backtrack(node.right, result, currentpath, currentSum + node.val, minsum);
currentpath.remove(currentpath.size() - 1);
}
}
static class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode() {}
public TreeNode(int val) { this.val = val; }
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
static class QItem {
TreeNode node;
int depth;
public QItem(TreeNode node, int depth) {
this.node = node;
this.depth = depth;
}
}
static void printLevelOrder(TreeNode root) {
LinkedList<QItem> queue = new LinkedList<>();
ArrayList<TreeNode> level = new ArrayList<>();
int depth = height(root);
queue.add(new QItem(root, depth));
for (; ; ) {
QItem curr = queue.poll();
if (curr.depth < depth) {
depth = curr.depth;
for (int i = (int) Math.pow(2, depth) - 1; i > 0; i--) {
out.print(" ");
}
for (TreeNode n : level) {
out.print(n == null ? " " : n.val);
for (int i = (int) Math.pow(2, depth + 1); i > 1; i--) {
out.print(" ");
}
}
out.println();
level.clear();
if (curr.depth <= 0) {
break;
}
}
level.add(curr.node);
if (curr.node == null) {
queue.add(new QItem(null, depth - 1));
queue.add(new QItem(null, depth - 1));
} else {
queue.add(new QItem(curr.node.left, depth - 1));
queue.add(new QItem(curr.node.right, depth - 1));
}
}
}
static int height(TreeNode root) {
return root == null ? 0 : 1 + Math.max(
height(root.left), height(root.right)
);
}
static void printTree(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode temp = q.poll();
out.print(" " + temp.val + " ");
if (temp.left != null) q.offer(temp.left);
if (temp.right != null) q.offer(temp.right);
}
out.println();
}
}
}
I am using backtracking to visit all nodes, I think time complexity of my solution would be O(N) (since all the nodes should be visited, please correct me if am wrong)
Every call of currentpath.add should be mirrored by a call of currentpath.remove. Your code does this fine, except in the bock below:
if (node.left == null && node.right == null) {
if (currentSum + node.val < minsum[0]) {
minsum[0] = currentSum + node.val;
currentpath.add(node.val);
result.clear();
result.addAll(new ArrayList<>(currentpath));
return;
}
}
So add that call of remove just before return.
Sorry in advance for all the code provided, because I am unsure where the problem may be, I am adding the whole thing.
I am having trouble getting my program to output anything (just blank space). A great deal of this code comes straight from our book and what isn't is also from previous (yet similar) programs that I have gotten to work. I have been mainly focusing on the levelOrder and insert methods, though I'm thinking it may be the latter.
import java.util.Scanner;
import java.lang.*;
public class AVLTree {
private static class AvlNode {
int key;
AvlNode left;
AvlNode right;
int height; //height difference between right and left subtrees at node
AvlNode(int x) {
key = x;
left = right = null;
height = 0;
}
AvlNode( int x, AvlNode l, AvlNode r) {
key = x;
left = l;
right = r;
}
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean keepRunning = true;
while (keepRunning) {
System.out.print(">> Enter choice [1-7] from menu below: \n");
System.out.println("\t 1) Insert node");
System.out.println("\t 2) Remove node");
System.out.println("\t 3) Print level order");
System.out.println("\t 4) Exit program ");
int choice = input.nextInt();
int value;
switch (choice)
{
case 1:
System.out.print("Enter element to insert: ");
value = input.nextInt();
insert(value, root);
break;
case 2:
System.out.print("Enter element to remove: ");
value = input.nextInt();
remove(value);
break;
case 3:
levelOrder();
System.out.println("");
break;
case 4:
keepRunning = false;
break;
default:
System.out.println("Invalid Choice!");
keepRunning = false;
}
}
}
private static AvlNode root;
public AvlNode getroot() {
return root;
}
private static int height(AvlNode t) {
if(t == null) {
return 1;
}
else
return t.height;
}
private static final int ALLOWED_IMBALANCE = 1;
private static AvlNode balance(AvlNode t) {
if (t == null) {
return t;
}
if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) {
if (height(t.left.left) >= height(t.left.right)) {
t = singleRotateLL(t);
} else {
t = doubleRotateLR(t);
}
} else {
if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) {
if (height(t.right.right) >= height(t.right.left)) {
t = singleRotateRL(t);
} else {
t = doubleRotateRL(t);
}
}
}
t.height = Math.max(height(t.left), height(t.right)) + 1;
return t;
}
//public methods for insert, remove, findMin, findMax, find....
//The find function will not require modification because they do not change the structure of the tree
private static AvlNode singleRotateLL(AvlNode k2) {
AvlNode k1 = k2.left; //next make "poiner" adjustments for the LL rotate operation
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
return k1;
}
private static AvlNode doubleRotateLR(AvlNode k3) {
AvlNode k1 = k3.left; //next make "poiner" adjustments for the LL rotate operation
AvlNode k2 = k1.right;
k1.right = k2.left;
k3.left = k2.right;
k2.left = k1;
k2.right = k3;
k1.height = Math.max(height(k1.left), height(k1.right)) + 1;
k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
k3.height = Math.max(height(k3.left), height(k3.right)) + 1;
return k2;
}
private static AvlNode singleRotateRL(AvlNode k2) {
AvlNode k1 = k2.right; //next make "poiner" adjustments for the LL rotate operation
k2.right = k1.left;
k1.left = k2;
k2.height = Math.max(height(k2.right), height(k2.left)) + 1;
k1.height = Math.max(height(k1.right), height(k1.left)) + 1;
return k1;
}
private static AvlNode doubleRotateRL(AvlNode k3) {
AvlNode k1 = k3.right; //next make "poiner" adjustments for the LL rotate operation
AvlNode k2 = k1.left;
k1.left = k2.right;
k3.right = k2.left;
k2.right = k1;
k2.left = k3;
k1.height = Math.max(height(k1.right), height(k1.left)) + 1;
k2.height = Math.max(height(k2.right), height(k2.left)) + 1;
k3.height = Math.max(height(k3.right), height(k3.left)) + 1;
return k2;
}
private static AvlNode insert(int x, AvlNode t) {
if(t == null)
return new AvlNode(x, null, null);
int compareResult = Integer.compare(x, t.key);
if(compareResult < 0) {
t.left = insert(x, t.left);
}
else if(compareResult > 0) {
t.right = insert(x, t.right);
}
else; // duplicate, do nothing
return balance(t);
}
public int findMin() {
return findMin(root).key;
}
private static AvlNode findMin(AvlNode t) {
if (t == null) {
return null;
}
if (t.left == null) {
return t;
}
return findMin(t.left);
}
public static void remove(int x) {
remove(x, root);
}
private static AvlNode remove(int x, AvlNode t) {
if (t == null) {
return t;
}
int compareResult = Integer.compare(x, t.key);
if (compareResult < 0) {
t.left = remove(x, t.left);
}
else if (compareResult > 0) {
t.right = remove(x, t.right);
}
else if ((t.left != null) && (t.right != null)) {
t.key = findMin(t.right).key;
t.right = remove(t.key, t.right);
}
else {
t = (t.left != null) ? t.left : t.right;
}
return balance(t);
}
private static void levelOrder() { //prints the level order traversal of the tree
int h = height(root);
for(int i = 1; i <= h; i++) {
printLevel(root, i);
}
}
private static void printLevel(AvlNode t, int level) {
if(t == null) {
return;
}
if(level == 1) {
System.out.print(t.key + " ");
}
else if(level > 1) {
printLevel(t.left, level - 1);
printLevel(t.right, level - 1);
}
}
}
You had to do two changes, one is to initialize root and the first time, and the second one is to change the height accordingly.
Just change the following class & function :
private static AvlNode insert(int x, AvlNode t) {
if (t == null && root==null)
return (root = new AvlNode(x, null, null));
else if (t==null) {
return new AvlNode(x, null, null);
}
t.height++;
int compareResult = Integer.compare(x, t.key);
if (compareResult < 0) {
t.left = insert(x, t.left);
} else if (compareResult > 0) {
t.right = insert(x, t.right);
} else {
t.height--;
}
return balance(t);
}
private static class AvlNode {
int key;
AvlNode left;
AvlNode right;
int height=0;
AvlNode(int x, AvlNode l, AvlNode r) {
key = x;
left = l;
right = r;
this.height++;
}
}
I am trying to implement Red Black tree after studying about it but getting error while printing the Red Black tree. Can you please have a look and suggest whether there is anything wrong in the implementation of the Red Black Tree insertion.
It shows only root and it's first left and right child recursively and then shows the following error :
Exception in thread "main" java.lang.StackOverflowError
at java.io.FileOutputStream.write(FileOutputStream.java:326)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.PrintStream.write(PrintStream.java:482)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at RedBlackTree.preOrder(RedBlackTree.java:161)
at RedBlackTree.preOrder(RedBlackTree.java:162)
at RedBlackTree.preOrder(RedBlackTree.java:162)
at RedBlackTree.preOrder(RedBlackTree.java:163)
Last two lines of error is repeated many times.
For print command I am using simple Pre-Order recursive code.
Following is the code :
public class RedBlackTree {
public RBNode root;
void leftRotate(RBNode node)
{
RBNode y;
y = node.right;
if(y.left != null)y.left.parent = node;
y.parent = node.parent;
if(node.parent == null)root = y;
else
{
if(node == node.parent.left)node.parent.left = y;
else node.parent.right =y;
}
y.left = node;
node.parent = y;
}
void rightRotate(RBNode node)
{
RBNode y;
y = node.left;
if(y.right != null)y.right.parent = node;
y.parent = node.parent;
if(node.parent == null)root = y;
else
{
if(node == node.parent.right)node.parent.right = y;
else node.parent.left =y;
}
y.right = node;
node.parent = y;
}
void insertNode(RBNode node, RBNode data)
{
// INSERT IN ROOT
if(node == null)
{
node = new RBNode(data.key);
root = node;
root.color = 0;
System.out.println("Root " + root.key);
}
else if (data.key < node.key && node.left == null)
{
node.left = data;
data.parent = node;
}
else if(data.key >node.key && node.right == null)
{
node.right = data;
data.parent = node;
}
else{
if(data.key < node.key)insertNode(node.left, data);
else insertNode(node.right, data);
}
data.color = 1;
RBNode uncle;
//Check REB BLACK PROPERTIES
while(data.parent != null && data.parent.color ==1 && data != root && data.color != 0)
{
System.out.println("Data " + data.key + " Parent " + data.parent.key);
//PARENT IS RIGHT CHILD
if(data.parent == data.parent.parent.right)
{
System.out.println("Parent RIGHT");
uncle = data.parent.parent.left;
if(uncle == null) System.out.println("Uncle is null");
//UNCLE IS BLACK OR NULL
if(uncle == null || uncle.color == 0)
{
System.out.println("Uncle BLACK or NULL");
if(data == data.parent.left)
{
System.out.println("Node is LEFT");
data = data.parent;
rightRotate(data);
}
data.parent.color = 0;
if(data.parent.parent.key != root.key)data.parent.parent.color = 1;
leftRotate(data.parent.parent);
}
//UNCLE IS RED
else
{
System.out.println("Uncle RED");
data.parent.parent.left.color = 0;
data.parent.color = 0;
if(data.parent.parent.key != root.key)data.parent.parent.color = 1;
data = data.parent;
}
}
// PARENT IS LEFT CHILD
else
{
System.out.println("Parent LEFT");
uncle = data.parent.parent.right;
//UNCLE IS NULL OR BLACK
if(uncle ==null || uncle.color == 0)
{
System.out.println("Uncle BLACK or NULL");
System.out.println("");
if(data == data.parent.right)
{
System.out.println("Node is RIGHT");
data = data.parent;
leftRotate(data);
}
data.parent.color = 0;
if(data.parent.parent.key != root.key)data.parent.parent.color = 1;
rightRotate(data.parent.parent);
}
//UNCLE IS RED
else
{
System.out.println("Uncle RED");
data.parent.parent.right.color = 0;
data.parent.color = 0;
if(data.parent.parent.key != root.key)data.parent.parent.color= 1;
data = data.parent;
}
}
}
root.color = 0;
}
void preOrder(RBNode node)
{
if(node != null)
{
System.out.println("Value : " + node.key + "Color: " + node.color);
preOrder(node.left);
preOrder(node.right);
}
}
public static void main(String args[])
{
RedBlackTree tree = new RedBlackTree();
tree.insertNode(tree.root, new RBNode(2));
tree.insertNode(tree.root, new RBNode(1));
tree.insertNode(tree.root, new RBNode(4));
tree.insertNode(tree.root, new RBNode(5));
tree.insertNode(tree.root, new RBNode(9));
tree.insertNode(tree.root, new RBNode(3));
tree.insertNode(tree.root, new RBNode(6));
tree.insertNode(tree.root, new RBNode(7));
tree.preOrder(tree.root);
}
}
class RBNode
{
int key;
RBNode parent;
RBNode left;
RBNode right;
int color; // 1 = RED , 0 = BLACK
public RBNode(int key)
{
this.key = key;
this.parent = null;
this.left = null;
this.right = null;
}
}
Is the insertion implementation wrong?
I am able to resolve that particular error so code is still not giving the entire correct answer. Error was coming out because of wrong implementation of Left and Right rotation.
void leftRotate(RBNode node)
{
RBNode y;
y = node.right;
node.right = y.left;
if(y.left != null)y.left.parent = node;
y.parent = node.parent;
if(node.parent == null)root = y;
else
{
if(node == node.parent.left)node.parent.left = y;
else node.parent.right =y;
}
y.left = node;
node.parent = y;
}
void rightRotate(RBNode node)
{
RBNode y;
y = node.left;
node.left = y.right;
if(y.right != null)y.right.parent = node;
y.parent = node.parent;
if(node.parent == null)root = y;
else
{
if(node == node.parent.right)node.parent.right = y;
else node.parent.left =y;
}
y.right = node;
node.parent = y;
}
I want to implement the Java AVL tree and to rotate the tree left and right. I am not getting this.
Can anybody by looking at the code below tell me how can I possibly rotate the tree left and right and then use fix up with those two functions to balance the AVL tree?
I hope someone here can guide me through this.
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
public class AVLTree<T> extends
BinarySearchTree<AVLTree.Node<T>, T> implements SSet<T> {
Random rand;
public static class Node<T> extends BSTNode<Node<T>,T> {
int h; // the height of the node
}
public AVLTree() {
sampleNode = new Node<T>();
rand = new Random();
c = new DefaultComparator<T>();
}
public int height(Node<T> u) {
return (u == null) ? 0 : u.h;
}
public boolean add(T x) {
Node<T> u = new Node<T>();
u.x = x;
if (super.add(u)) {
for (Node<T> w = u; w != nil; w = w.parent) {
// walk back up to the root adjusting heights
w.h = Math.max(height(w.left), height(w.right)) + 1;
}
fixup(u);
return true;
}
return false;
}
public void splice(Node<T> u) {
Node<T> w = u.parent;
super.splice(u);
for (Node<T> z = u; z != nil; z = z.parent)
z.h = Math.max(height(z.left), height(z.right)) + 1;
fixup(w);
}
public void checkHeights(Node<T> u) {
if (u == nil) return;
checkHeights(u.left);
checkHeights(u.right);
if (height(u) != 1 + Math.max(height(u.left), height(u.right)))
throw new RuntimeException("Check heights shows incorrect heights");
int dif = height(u.left) - height(u.right);
if (dif < -1 || dif > 1)
throw new RuntimeException("Check heights found height difference of " + dif);
}
/**
* TODO: finish writing this method
* #param u
*/
public void fixup(Node<T> u) {
while (u != nil) {
int dif = height(u.left) - height(u.right);
if (dif > 1) {
// TODO: add code here to fix AVL condition
// on the path from u to the root, if necessary
} else if (dif < -1) {
// TODO: add code here to fix AVL condition
// on the path from u to the root, if necessary
}
u = u.parent;
}
}
public Node rotateLeft() {
return rotateLeft(u.parent);
}
public void rotateLeft(Node<T> u) {
// TODO: Recompute height values at u and u.parent
}
public void rotateRight(Node<T> u) {
// TODO: Recompute height values at u and u.parent
}
public static <T> T find(SortedSet<T> ss, T x) {
SortedSet<T> ts = ss.tailSet(x);
if (!ts.isEmpty()) {
return ts.first();
}
return null;
}
/**
* This just does some very basic correctness testing
* #param args
*/
public static void main(String[] args) {
AVLTree<Integer> t = new AVLTree<Integer>();
Random r = new Random(0);
System.out.print("Running AVL tests...");
int n = 1000;
for (int i = 0; i < n; i++) {
t.add(r.nextInt(2*n));
t.checkHeights(t.r);
}
for (int i = 0; i < n; i++) {
t.remove(r.nextInt(2*n));
t.checkHeights(t.r);
}
System.out.println("done");
t.clear();
System.out.print("Running correctness tests...");
n = 100000;
SortedSet<Integer> ss = new TreeSet<Integer>();
Random rand = new Random();
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
boolean b1 = t.add(x);
boolean b2 = ss.add(x);
if (b1 != b2) {
throw new RuntimeException("Adding " + x + " gives " + b2
+ " in SortedSet and " + b1 + " in AVL Tree");
}
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
Integer x1 = t.find(x);
Integer x2 = find(ss, x);
if (x1 != x2) {
throw new RuntimeException("Searching " + x + " gives " + x2
+ " in SortedSet and " + x1 + " in AVL Tree");
}
ss.headSet(x);
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
boolean b1 = t.remove(x);
boolean b2 = ss.remove(x);
if (b1 != b2) {
throw new RuntimeException("Error (2): Removing " + x + " gives " + b2
+ " in SortedSet and " + b1 + " in AVL Tree");
}
}
for (int i = 0; i < n; i++) {
Integer x = rand.nextInt(2*n);
Integer x1 = t.find(x);
Integer x2 = find(ss, x);
if (x1 != x2) {
throw new RuntimeException("Error (3): Searching " + x + " gives " + x2
+ " in SortedSet and " + x1 + " in AVL Tree");
}
ss.headSet(x);
}
System.out.println("done");
}
}
Full AVL tree implementation:
public class AVLTree<T> {
private AVLNode<T> root;
private static class AVLNode<T> {
private T t;
private int height;
private AVLNode<T> left;
private AVLNode<T> right;
private AVLNode(T t) {
this.t = t;
height = 1;
}
}
public void insert(T value) {
root = insert(root, value);
}
private AVLNode<T> insert(AVLNode<T> n, T v) {
if (n == null) {
n = new AVLNode<T>(v);
return n;
} else {
int k = ((Comparable) n.t).compareTo(v);
if (k > 0) {
n.left = insert(n.left, v);
} else {
n.right = insert(n.right, v);
}
n.height = Math.max(height(n.left), height(n.right)) + 1;
int heightDiff = heightDiff(n);
if (heightDiff < -1) {
if (heightDiff(n.right) > 0) {
n.right = rightRotate(n.right);
return leftRotate(n);
} else {
return leftRotate(n);
}
} else if (heightDiff > 1) {
if (heightDiff(n.left) < 0) {
n.left = leftRotate(n.left);
return rightRotate(n);
} else {
return rightRotate(n);
}
} else;
}
return n;
}
private AVLNode<T> leftRotate(AVLNode<T> n) {
AVLNode<T> r = n.right;
n.right = r.left;
r.left = n;
n.height = Math.max(height(n.left), height(n.right)) + 1;
r.height = Math.max(height(r.left), height(r.right)) + 1;
return r;
}
private AVLNode<T> rightRotate(AVLNode<T> n) {
AVLNode<T> r = n.left;
n.left = r.right;
r.right = n;
n.height = Math.max(height(n.left), height(n.right)) + 1;
r.height = Math.max(height(r.left), height(r.right)) + 1;
return r;
}
private int heightDiff(AVLNode<T> a) {
if (a == null) {
return 0;
}
return height(a.left) - height(a.right);
}
private int height(AVLNode<T> a) {
if (a == null) {
return 0;
}
return a.height;
}
}
Here's a full implementation of AVL tree in Java
class Node {
int key;
Node left;
Node right;
int height;
Node(int value) {
key = value;
left = null;
right = null;
height = 1;
}
}
class AVLTree {
Node root;
int height(Node root) {
if (root == null)
return 0;
return root.height;
}
int findHeight() {
return height(root);
}
int findHeightFrom(int value) {
Node node = search(root, value);
if (node == null)
return -1;
return node.height;
}
Node search(Node root, int value) {
if (root == null)
return null;
else {
if (value == root.key)
return root;
else if (value < root.key)
return search(root.left, value);
else
return search(root.right, value);
}
}
boolean find(int value) {
Node node = search(root,value);
if (node == null)
return false;
return true;
}
int max(int one, int two) {
return (one > two) ? one : two;
}
Node rightRotate(Node root) {
Node rootLeftChild = root.left;
root.left = rootLeftChild.right;
rootLeftChild.right = root;
root.height = max(height(root.left), height(root.right)) + 1;
rootLeftChild.height = max(height(rootLeftChild.left), height(rootLeftChild.right)) + 1;
return rootLeftChild;
}
Node leftRotate(Node root) {
Node rootRightChild = root.right;
root.right = rootRightChild.left;
rootRightChild.left = root;
root.height = max(height(root.left), height(root.right)) + 1;
rootRightChild.height = max(height(rootRightChild.left), height(rootRightChild.right)) + 1;
return rootRightChild;
}
Node insertNode(Node root, int value) {
if (root == null)
root = new Node(value);
else {
if (value < root.key)
root.left = insertNode(root.left, value);
else
root.right = insertNode(root.right, value);
}
root.height = max(height(root.left), height(root.right)) + 1;
int balanceFactor = height(root.left) - height(root.right);
if (balanceFactor > 1) {
// either left-left case or left-right case
if (value < root.left.key) {
// left-left case
root = rightRotate(root);
} else {
// left-right case
root.left = leftRotate(root.left);
root = rightRotate(root);
}
} else if (balanceFactor < -1) {
// either right-right case or right-left case
if (value > root.right.key) {
// right-right case
root = leftRotate(root);
} else {
// right-left case
root.right = rightRotate(root.right);
root = leftRotate(root);
}
}
return root;
}
void insert(int value) {
root = insertNode(root, value);
}
void inorder(Node root) {
if (root != null) {
inorder(root.left);
System.out.print(root.key + " ");
inorder(root.right);
}
}
void inorderTraversal() {
inorder(root);
System.out.println();
}
void preorder(Node root) {
if (root != null) {
System.out.print(root.key + " ");
preorder(root.left);
preorder(root.right);
}
}
void preorderTraversal() {
preorder(root);
System.out.println();
}
}
public class AVLTreeExample {
public static void main(String[] args) {
AVLTree avl = new AVLTree();
avl.insert(10);
avl.insert(20);
avl.insert(30);
avl.insert(40);
avl.insert(50);
avl.insert(25);
System.out.print("Inorder Traversal : "); avl.inorderTraversal();
System.out.print("Preorder Traversal : "); avl.preorderTraversal();
System.out.println("Searching for 10 : " + avl.find(10));
System.out.println("Searching for 11 : " + avl.find(11));
System.out.println("Searching for 20 : " + avl.find(20));
System.out.println("Height of the tree : " + avl.findHeight());
System.out.println("Finding height from 10 : " + avl.findHeightFrom(10));
System.out.println("Finding height from 20 : " + avl.findHeightFrom(20));
System.out.println("Finding height from 25 : " + avl.findHeightFrom(25));
}
}
in order to rotate it right
you need to first check if the parent is not root
then if the parent is the right of the grand parent
if so, set the right of the grand parent to the child
else, set the left of the gran parent to the child
otherwise,
root is child
For an assignment, we were instructed to create a priority queue implemented via a binary heap, without using any built-in classes, and I have done so successfully by using an array to store the queued objects. However, I'm interested in learning how to implement another queue by using an actual tree structure, but in doing so I've run across a bit of a problem.
How would I keep track of the nodes on which I would perform insertion and deletion? I have tried using a linked list, which appends each node as it is inserted - new children are added starting from the first list node, and deleted from the opposite end. However, this falls apart when elements are rearranged in the tree, as children are added at the wrong position.
Edit: Perhaps I should clarify - I'm not sure how I would be able to find the last occupied and first unoccupied leaves. For example, I would always be able to tell the last inserted leaf, but if I were to delete it, how would I know which leaf to delete when I next remove the item? The same goes for inserting - how would I know which leaf to jump to next after the current leaf has both children accounted for?
A tree implementation of a binary heap uses a complete tree [or almost full tree: every level is full, except the deepest one].
You always 'know' which is the last occupied leaf - where you delete from [and modifying it is O(logn) after it changed so it is not a problem], and you always 'know' which is the first non-occupied leaf, in which you add elements to [and again, modifying it is also O(logn) after it changed].
The algorithm idea is simple:
insert: insert element to the first non-occupied leaf, and use heapify [sift up] to get this element to its correct place in the heap.
delete_min: replace the first element with the last occupied leaf, and remove the last occupied leaf. then, heapify [sift down] the heap.
EDIT: note that delete() can be done to any element, and not only the head, however - finding the element you want to replace with the last leaf will be O(n), which will make this op expensive. for this reason, the delete() method [besides the head], is usually not a part of the heap data structure.
I really wanted to do this for almost a decade.Finally sat down today and wrote it.Anyone who wants it can use it.I got inspired by Quora founder to relearn Heap.Apparently he was asked how would you find K near points in a set of n points in his Google phone screen.Apparently his answer was to use a Max Heap and to store K values and remove the maximum element after the size of the heap exceeds K.The approach is pretty simple and the worst case is nlog K which is better than n^2 in most sorting cases.Here is the code.
import java.util.ArrayList;
import java.util.List;
/**
* #author Harish R
*/
public class HeapPractise<T extends Comparable<T>> {
private List<T> heapList;
public List<T> getHeapList() {
return heapList;
}
public void setHeapList(List<T> heapList) {
this.heapList = heapList;
}
private int heapSize;
public HeapPractise() {
this.heapList = new ArrayList<>();
this.heapSize = heapList.size();
}
public void insert(T item) {
if (heapList.size() == 0) {
heapList.add(item);
} else {
siftUp(item);
}
}
public void siftUp(T item) {
heapList.add(item);
heapSize = heapList.size();
int currentIndex = heapSize - 1;
while (currentIndex > 0) {
int parentIndex = (int) Math.floor((currentIndex - 1) / 2);
T parentItem = heapList.get(parentIndex);
if (parentItem != null) {
if (item.compareTo(parentItem) > 0) {
heapList.set(parentIndex, item);
heapList.set(currentIndex, parentItem);
currentIndex = parentIndex;
continue;
}
}
break;
}
}
public T delete() {
if (heapList.size() == 0) {
return null;
}
if (heapList.size() == 1) {
T item = heapList.get(0);
heapList.remove(0);
return item;
}
return siftDown();
}
public T siftDown() {
T item = heapList.get(0);
T lastItem = heapList.get(heapList.size() - 1);
heapList.remove(heapList.size() - 1);
heapList.set(0, lastItem);
heapSize = heapList.size();
int currentIndex = 0;
while (currentIndex < heapSize) {
int leftIndex = (2 * currentIndex) + 1;
int rightIndex = (2 * currentIndex) + 2;
T leftItem = null;
T rightItem = null;
int currentLargestItemIndex = -1;
if (leftIndex <= heapSize - 1) {
leftItem = heapList.get(leftIndex);
}
if (rightIndex <= heapSize - 1) {
rightItem = heapList.get(rightIndex);
}
T currentLargestItem = null;
if (leftItem != null && rightItem != null) {
if (leftItem.compareTo(rightItem) >= 0) {
currentLargestItem = leftItem;
currentLargestItemIndex = leftIndex;
} else {
currentLargestItem = rightItem;
currentLargestItemIndex = rightIndex;
}
} else if (leftItem != null && rightItem == null) {
currentLargestItem = leftItem;
currentLargestItemIndex = leftIndex;
}
if (currentLargestItem != null) {
if (lastItem.compareTo(currentLargestItem) >= 0) {
break;
} else {
heapList.set(currentLargestItemIndex, lastItem);
heapList.set(currentIndex, currentLargestItem);
currentIndex = currentLargestItemIndex;
continue;
}
}
}
return item;
}
public static void main(String[] args) {
HeapPractise<Integer> heap = new HeapPractise<>();
for (int i = 0; i < 32; i++) {
heap.insert(i);
}
System.out.println(heap.getHeapList());
List<Node<Integer>> nodeArray = new ArrayList<>(heap.getHeapList()
.size());
for (int i = 0; i < heap.getHeapList().size(); i++) {
Integer heapElement = heap.getHeapList().get(i);
Node<Integer> node = new Node<Integer>(heapElement);
nodeArray.add(node);
}
for (int i = 0; i < nodeArray.size(); i++) {
int leftNodeIndex = (2 * i) + 1;
int rightNodeIndex = (2 * i) + 2;
Node<Integer> node = nodeArray.get(i);
if (leftNodeIndex <= heap.getHeapList().size() - 1) {
Node<Integer> leftNode = nodeArray.get(leftNodeIndex);
node.left = leftNode;
}
if (rightNodeIndex <= heap.getHeapList().size() - 1) {
Node<Integer> rightNode = nodeArray.get(rightNodeIndex);
node.right = rightNode;
}
}
BTreePrinter.printNode(nodeArray.get(0));
}
}
public class Node<T extends Comparable<?>> {
Node<T> left, right;
T data;
public Node(T data) {
this.data = data;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class BTreePrinter {
public static <T extends Comparable<?>> void printNode(Node<T> root) {
int maxLevel = BTreePrinter.maxLevel(root);
printNodeInternal(Collections.singletonList(root), 1, maxLevel);
}
private static <T extends Comparable<?>> void printNodeInternal(
List<Node<T>> nodes, int level, int maxLevel) {
if (nodes.isEmpty() || BTreePrinter.isAllElementsNull(nodes))
return;
int floor = maxLevel - level;
int endgeLines = (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;
BTreePrinter.printWhitespaces(firstSpaces);
List<Node<T>> newNodes = new ArrayList<Node<T>>();
for (Node<T> node : nodes) {
if (node != null) {
String nodeData = String.valueOf(node.data);
if (nodeData != null) {
if (nodeData.length() == 1) {
nodeData = "0" + nodeData;
}
}
System.out.print(nodeData);
newNodes.add(node.left);
newNodes.add(node.right);
} else {
newNodes.add(null);
newNodes.add(null);
System.out.print(" ");
}
BTreePrinter.printWhitespaces(betweenSpaces);
}
System.out.println("");
for (int i = 1; i <= endgeLines; i++) {
for (int j = 0; j < nodes.size(); j++) {
BTreePrinter.printWhitespaces(firstSpaces - i);
if (nodes.get(j) == null) {
BTreePrinter.printWhitespaces(endgeLines + endgeLines + i
+ 1);
continue;
}
if (nodes.get(j).left != null)
System.out.print("//");
else
BTreePrinter.printWhitespaces(1);
BTreePrinter.printWhitespaces(i + i - 1);
if (nodes.get(j).right != null)
System.out.print("\\\\");
else
BTreePrinter.printWhitespaces(1);
BTreePrinter.printWhitespaces(endgeLines + endgeLines - i);
}
System.out.println("");
}
printNodeInternal(newNodes, level + 1, maxLevel);
}
private static void printWhitespaces(int count) {
for (int i = 0; i < 2 * count; i++)
System.out.print(" ");
}
private static <T extends Comparable<?>> int maxLevel(Node<T> node) {
if (node == null)
return 0;
return Math.max(BTreePrinter.maxLevel(node.left),
BTreePrinter.maxLevel(node.right)) + 1;
}
private static <T> boolean isAllElementsNull(List<T> list) {
for (Object object : list) {
if (object != null)
return false;
}
return true;
}
}
Please note that BTreePrinter is a code I took somewhere in Stackoverflow long back and I modified to use with 2 digit numbers.It will be broken if we move to 3 digit numbers and it is only for simple understanding of how the Heap structure looks.A fix for 3 digit numbers is to keep everything as multiple of 3.
Also due credits to Sesh Venugopal for wonderful tutorial on Youtube on Heap data structure
public class PriorityQ<K extends Comparable<K>> {
private class TreeNode<T extends Comparable<T>> {
T val;
TreeNode<T> left, right, parent;
public String toString() {
return this.val.toString();
}
TreeNode(T v) {
this.val = v;
left = null;
right = null;
}
public TreeNode<T> insert(T val, int position) {
TreeNode<T> parent = findNode(position/2);
TreeNode<T> node = new TreeNode<T>(val);
if(position % 2 == 0) {
parent.left = node;
} else {
parent.right = node;
}
node.parent = parent;
heapify(node);
return node;
}
private void heapify(TreeNode<T> node) {
while(node.parent != null && (node.parent.val.compareTo(node.val) < 0)) {
T temp = node.val;
node.val = node.parent.val;
node.parent.val = temp;
node = node.parent;
}
}
private TreeNode<T> findNode(int pos) {
TreeNode<T> node = this;
int reversed = 1;
while(pos > 0) {
reversed <<= 1;
reversed |= (pos&1);
pos >>= 1;
}
reversed >>= 1;
while(reversed > 1) {
if((reversed & 1) == 0) {
node = node.left;
} else {
node = node.right;
}
reversed >>= 1;
}
return node;
}
public TreeNode<T> remove(int pos) {
if(pos <= 1) {
return null;
}
TreeNode<T> last = findNode(pos);
if(last.parent.right == last) {
last.parent.right = null;
} else {
last.parent.left = null;
}
this.val = last.val;
bubbleDown();
return null;
}
public void bubbleDown() {
TreeNode<T> node = this;
do {
TreeNode<T> left = node.left;
TreeNode<T> right = node.right;
if(left != null && right != null) {
T max = left.val.compareTo(right.val) > 0 ? left.val : right.val;
if(max.compareTo(node.val) > 0) {
if(left.val.equals(max)) {
left.val = node.val;
node.val = max;
node = left;
} else {
right.val = node.val;
node.val = max;
node = right;
}
} else {
break;
}
} else if(left != null) {
T max = left.val;
if(left.val.compareTo(node.val) > 0) {
left.val = node.val;
node.val = max;
node = left;
} else {
break;
}
} else {
break;
}
} while(true);
}
}
private TreeNode<K> root;
private int position;
PriorityQ(){
this.position = 1;
}
public void insert(K val) {
if(val == null) {
return;
}
if(root == null) {
this.position = 1;
root = new TreeNode<K>(val);
this.position++;
return ;
}
root.insert(val, position);
position++;
}
public K remove() {
if(root == null) {
return null;
}
K val = root.val;
root.remove(this.position-1);
this.position--;
if(position == 1) {
root = null;
}
return val;
}
public static void main(String[] args) {
PriorityQ<Integer> q = new PriorityQ<>();
System.out.println(q.remove());
q.insert(1);
q.insert(11);
q.insert(111);
q.insert(1111);
q.remove();
q.remove();
q.remove();
q.remove();
q.insert(2);
q.insert(4);
}
}