I'm writing an AVL Tree class and my professor has included some tests for our code. I have passed all the tests except three, and the three tests I'm failing seem to indicate that when elements are added to or removed from the tree, the tree doesn't balance itself when necessary. I've been trying to debug it, but I just can't seem to find the error. Could someone please point out what I'm missing?
EDIT:
Failed tests:
RemoveRoot - removes the root of the AVL tree and replaces it with its successor. AddManySingle - adds several elements and forces single rotation. AddManyDouble - adds several elements and forces double rotation.
private int count, height;
private AVLNode < E > root;
public AVLTree() {
root = null;
count = 0;
height = 0;
}
//the private inner Node class
private class AVLNode < E > {
private int height, bf;
private E data;
private AVLNode < E > left, right;
public AVLNode() {
data = null;
left = right = null;
bf = 0;
height = 0;
}
public AVLNode(E data) {
this.data = data;
left = right = null;
bf = 0;
height = 0;
}
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
public AVLNode < E > getLeft() {
return left;
}
public void setLeft(AVLNode < E > left) {
this.left = left;
}
public AVLNode < E > getRight() {
return right;
}
public void setRight(AVLNode < E > right) {
this.right = right;
}
public int getBF() {
return bf;
}
public void setBF() {
if (right == null && left == null) {
bf = 0;
} else if (right == null) {
bf = this.getLeft().getHeight();
} else if (left == null) {
bf = 0 - this.getRight().getHeight();
} else {
this.bf = this.getLeft().getHeight() - this.getRight().getHeight();
}
}
public void setBF(int theBalanceFactor) {
bf = theBalanceFactor;
}
/**
* The getHeight method computes the height of an AVL tree.
* #return The height of the AVL tree.
*/
public int getHeight() {
return this == null ? -1 : this.height;
}
public void setHeight() {
int leftHeight = (left == null) ? -1 : left.getHeight();
int rightHeight = (right == null) ? -1 : right.getHeight();
height = 1 + Math.max(leftHeight, rightHeight);
}
public void setHeight(int theHeight) {
height = theHeight;
}
}
//the private inner Iterator class
private class AVLIterator implements Iterator < E > {
private AVLNode < E > nextNode;
private Stack < AVLNode < E >> stack;
public AVLIterator() {
nextNode = root;
stack = new Stack < AVLNode < E >> ();
while (root != null) {
stack.push(root);
root = root.getLeft();
}
}
//Returns true if the iteration has more datas.
#Override
public boolean hasNext() {
return !stack.isEmpty();
}
//Returns the next data in the iteration.
#Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException("No next element.");
}
AVLNode < E > node = stack.pop();
E result = node.data;
if (node.right != null) {
node = node.right;
while (node != null) {
stack.push(node);
node = node.left;
}
}
return result;
}
//Removes the last data in the iteration.
#Override
public void remove() {
throw new UnsupportedOperationException("Invalid operation for support list.");
}
}
/**
* Rotate binary tree node that has a right child.
* Update heights, then return new root.
* n1 is the imbalanced node
*/
private AVLNode < E > rotateWithRightChild(AVLNode < E > n1) {
AVLNode < E > n2 = n1.right;
n1.right = n2.left;
n2.left = n1;
return n2;
}
/**
* Rotate binary tree node that has a left child.
* Update heights, then return new root.
*/
private AVLNode < E > rotateWithLeftChild(AVLNode < E > n2) {
AVLNode < E > n1 = n2.left;
n2.left = n1.right;
n1.right = n2;
return n1;
}
/**
* Double rotate binary tree node: first left child
* with its right child; then node n3 with new left child.
* Update heights, then return new root.
*/
private AVLNode < E > doubleWithLeftChild(AVLNode < E > n3) {
n3.left = rotateWithRightChild(n3.left);
return rotateWithLeftChild(n3);
}
/**
* Double rotate binary tree node: first right child
* with its left child; then node n1 with new right child.
* Update heights, then return new root.
*/
private AVLNode < E > doubleWithRightChild(AVLNode < E > n1) {
n1.right = rotateWithLeftChild(n1.right);
return rotateWithRightChild(n1);
}
//updates height and balance factor
private void updateHeightAndBF(AVLNode < E > node) {
int leftHeight, rightHeight, bf = 0, height = 0;
if (node != null) {
if (node.getLeft() == null) {
leftHeight = -1;
} else {
leftHeight = node.left.height;
}
if (node.getRight() == null) {
rightHeight = -1;
} else {
rightHeight = node.right.height;
}
/*if (leftHeight >= rightHeight) {
height = leftHeight + 1;
} else if (rightHeight >= leftHeight) {
height = rightHeight + 1;
}*/
height = Math.max(leftHeight, rightHeight) + 1;
bf = leftHeight - rightHeight;
node.setHeight(height);
node.setBF(bf);
} else {
height = -1;
}
}
/**
* private helper method.
* Balances a node by updating balance
* factor when a node is removed from
* or added to the AVL tree.
*
* #param node the node that is being balanced
*/
private AVLNode < E > balance(AVLNode < E > node) {
int hLeft, hRight;
if (node == null) {
return node;
}
if (node.bf == 2) {
if (node.left.bf == 1) {
node.left = rotateWithLeftChild(node);
} else if (node.left.bf == -1) {
node.left = doubleWithLeftChild(node);
}
} else if (node.bf == -2) {
if (node.right.bf < 0) {
node.right = rotateWithRightChild(node);
} else if (node.right.bf == -1) {
node.right = doubleWithRightChild(node);
}
}
return node;
}
/**
* Adds the item to the tree. Duplicate items and null items should not be added. O(log n)
*
* #param item the item to add
* #return true if item added, false if it was not
*/
#Override
public boolean add(E item) { // TODO
int theSize = size();
if (root == null && item != null) { //null check here for item
root = new AVLNode < E > (item);
count++;
return true;
} else if (item == null) {
return false;
} else {
add(root, item);
root = balance(root);
}
return (count != theSize);
}
/**
* private helper method for the add() method.
* Adds the item to the tree. Duplicate items and null items should not be added.
* Runs in O(log n) expected time, may be linear time in worst case
*
* #param value the item to add
* #return true if item added, false if it was not
*/
private boolean add(AVLNode < E > node, E value) { // TODO
if (value.equals(node.getData()) || value == null) {
//if it's a duplicate or null
return false;
}
if (value.compareTo(node.data) < 0) {
AVLNode < E > left = node.left;
if (left == null) {
node.left = new AVLNode < E > (value);
count++;
updateHeightAndBF(node);
balance(node);
return true;
} else updateHeightAndBF(node);
balance(node);
return add(left, value);
} else if (value.compareTo(node.data) > 0) {
AVLNode < E > right = node.right;
if (right == null) {
node.right = new AVLNode < E > (value);
count++;
updateHeightAndBF(node);
balance(node);
return true;
} else {
updateHeightAndBF(node);
balance(node);
return add(right, value);
}
}
return false;
}
/**
* returns the maximum data held in the tree. null if tree is empty.
* runs in O(log n) expected, may be linear in worst case
*
* #return maximum item or null if empty
*/
#Override
public E max() {
if (isEmpty()) {
return null;
}
return max(root).data;
}
/**
* a private helper method for the max() method.
*
* #return maximum Node or null if empty
*/
private AVLNode < E > max(AVLNode < E > x) {
if (x.getRight() == null) { //the rightmost node from the root
//is larger than the root, which is larger than the leftmost
//node from the root. so, if the rightmost node is null,
// that means the root node is the maximum data in the tree
return x;
} else {
return max(x.getRight());
}
}
/**
* returns the number of items in the tree O(1) with variable
*
* #return the number of items in the tree
*/
#Override
public int size() {
return count;
}
/**
* O(1)
* #return true if tree has no datas, false if tree has anything in it.
*/
#Override
public boolean isEmpty() {
return size() == 0;
}
/**
* runs in O(n) worst case, and O(log n) average case.
* #return the minimum data in the tree or null if empty
*/
#Override
public E min() {
if (isEmpty()) {
return null;
}
return min(root).data;
}
/**
* private helper method for the min() method
*
* #return the minimum Node in the tree or null if empty
*/
private AVLNode < E > min(AVLNode < E > y) {
if (y == null) {
return null;
} else if (y.left == null) { //the leftmost node from the root
//is smaller than the root, which is smaller than the rightmost
//node. so, if the leftmost node is null,
// that means the root node is the minimum data in the tree
return y;
} else {
return min(y.left);
}
}
/**
* Checks for the given item in the tree. O(log n)
*
* #param item the item to look for
* #return true if item is in tree, false otherwise
*/
#Override
public boolean contains(E item) {
return contains(root, item);
}
/**
* private helper method for the contains() methods
* Checks for the given item in the tree.
* runs in O(log n) expected, may be linear in worst case
*
* #param root the starting point
* #param item the item to look for
* #return true if item is in tree, false otherwise
*/
private boolean contains(AVLNode < E > root, E item) {
if (root == null || isEmpty()) {
return false;
}
if (item.compareTo(root.getData()) == 0) { //if item is
//equal to the data in the root Node, return true
return true;
} else {
if (item.compareTo(root.getData()) < 0) { //if item is less than data
AVLNode < E > left = root.getLeft(); //go to the left node
return (contains(left, item)); //call contains() method with the left node
} else if (item.compareTo(root.getData()) > 0) { //if item is more than data
AVLNode < E > right = root.getRight(); //go to the right node
return (contains(right, item)); //call contains() method with the right node
} else {
return true;
}
}
}
/**
* removes the given item from the tree O(log n). if the item is found
* and removed, balance the tree
*
* #param item the item to remove
* #return true if item removed, false if item not found
*/
#Override
public boolean remove(E item) {
int theSize = size();
root = remove(root, item);
return (count != theSize);
}
/**
* private helper method for the remove() method
* removes the given item from the tree
* runs in O(log n) expected, may be linear in worst case
* uses in-order successor
*
* #param node the starting point
* #param item the item to remove
* #return the node if the specified is node in the tree, null otherwise
*/
private AVLNode < E > remove(AVLNode < E > node, E item) { //TODO
if (node == null || item == null) {
return null;
}
if (root == null) {
return root;
}
if (item.compareTo(node.data) < 0) {
updateHeightAndBF(node);
balance(node);
node.left = remove(node.left, item);
} else if (item.compareTo(node.data) > 0) {
updateHeightAndBF(node);
balance(node);
node.right = remove(node.right, item);
} else if (node.left != null && node.right != null) { //two child nodes
AVLNode < E > succ = min(node.right);
node.data = succ.data;
updateHeightAndBF(node);
balance(node);
node.right = remove(node.right, node.data);
} else {
node = (node.left != null) ? node.left : node.right;
count--;
updateHeightAndBF(node);
return balance(node);
}
return node;
}
/**
* Runs in linear time, O(n)
* #return a list of the data in post-order traversal order
*/
#Override
public List < E > getPostOrder() {
List < E > postOrderList = new ArrayList < E > (size());
recPostOrder(root, postOrderList);
return postOrderList;
}
/**
* private helper method for the getPostOrder() method
* Runs in linear time, O(n)
*/
private void recPostOrder(AVLNode < E > theRoot, List < E > theList) {
if (theRoot != null) {
recPostOrder(theRoot.left, theList);
recPostOrder(theRoot.right, theList);
theList.add(theRoot.data);
}
}
/**
* Runs in linear time, O(n)
* #return a list of the data in pre-order traversal order
*/
#Override
public List < E > getPreOrder() {
List < E > preOrderList = new ArrayList < E > (size());
recPreOrder(root, preOrderList);
return preOrderList;
}
/**
* private helper method for the getPreOrder() method
* Runs in linear time, O(n)
*
*/
private void recPreOrder(AVLNode < E > theRoot, List < E > theList) {
if (theRoot != null) {
theList.add(theRoot.getData());
recPreOrder(theRoot.getLeft(), theList);
recPreOrder(theRoot.getRight(), theList);
}
}
/**
* Runs in linear time
* #return a list of the data in pre-order traversal order
*/
public List < E > getInOrder() {
List < E > inOrderList = new ArrayList < E > (size());
recInOrder(root, inOrderList);
return inOrderList;
}
/**
*
* private helper method for the getInOrder() method
* Runs in linear time
*
*/
private void recInOrder(AVLNode < E > theRoot, List < E > theList) {
if (theRoot != null) {
recInOrder(theRoot.left, theList);
theList.add(theRoot.data);
recInOrder(theRoot.right, theList);
}
}
/**
* Runs in linear time, O(n)
* #return a list of the data in level-order traversal order
*/
#Override
public List < E > getLevelOrder() {
List < E > data = new ArrayList < E > ();
Queue < AVLNode < E >> queue = new LinkedList < AVLNode < E >> ();
if (this.isEmpty()) {
return data;
} else {
queue.add(root);
}
while (!queue.isEmpty()) {
AVLNode < E > x = queue.remove();
if (x != null) {
data.add(x.getData());
if (x.getLeft() != null) {
queue.add(x.getLeft());
}
if (x.getRight() != null) {
queue.add(x.getRight());
}
}
}
return data;
}
/**
* O(1) [ignore garbage collection costs]
*
* Removes all the datas from this tree
*/
#Override
public void clear() {
root = null;
count = 0;
}
/**
* returns an iterator over this collection
* iterator is based on an in-order traversal
*/
#Override
public Iterator < E > iterator() {
return new AVLIterator();
}
}
Related
I wrote the following class for building a LinkedList with single values on top of a given code template.
.
.
public class LinkedElement<T> {
private T name;
private LinkedElement<T> link;
public LinkedElement(T value) {
this.name = value;
}
/**
* Returns the value of the i-th linked element, assuming the current element to
* be at index 0.
*
* #param i 0-based index of the element whose value to return.
* #return the i-th element's value, or {#code null} if there is no element with
* that index.
*/
public T get(int i) {
int iterator = i;
if (iterator == 0) {
return this.name;
}
if (this.link == null) {
iterator = 0;
return null;
}
if (iterator > 0) {
iterator = iterator - 1;
return this.link.get(iterator);
}
return null;
}
/**
* Adds a new linked element holding the given value at the end of the linked
* elements.
*
* #param newVal the new value.
*/
public void add(T newVal) {
if (this.link == null) {
this.link = new LinkedElement(newVal);
} else {
this.link.add(newVal);
}
}
**/**
* Removes the i-th element from the linked elements. If {#code i == 0}, this
* will effectively remove the head element. Thus, this method returns the
* linked element that is the new head element.
*
* #param i index of the element to remove.
* #return the new head element.
*/
public LinkedElement<T> remove(int i) {
// Store i as changeable iterator
int iterator = i;
// Store current head element;
LinkedElement<T> tempNode = this;
// If head element itself is to be removed
if (iterator == 0) {
if (this.link != null) {
this.name = this.link.name;
this.link = this.link.link;
}
if (this.link == null) {
this.name = null;
this.link = null;
}
return this;
// If the element is further down in the linkedlist
// iterate through list and invoke "remove" at the desired position inside
// the list
}
if (iterator > 0) {
iterator = iterator - 1;
return this.link.remove(iterator);
}
return null;**
}
}
The "remove" method seems to work fine when I remove just one element and print the elements out one by one. The trouble starts when I declare a new headElement through a remove method (which returns the new headElement in that respective list)
public static void main(String[] args) {
// An example
LinkedElement<String> headElement = new LinkedElement<String>("Yo!");
headElement.add("LA");
headElement.add("is");
headElement.add("about");
headElement.add("to");
headElement.add("witness");
headElement.add("another");
headElement.add("sunny");
headElement.add("day!");
System.out.println(headElement.get(7)); // prints "sunny"
headElement = headElement.remove(6); // removes "another"
headElement = headElement.remove(0); // removes "Yo!"
System.out.println(headElement.get(0)); // prints "sunny"
}
The expected output should be:
sunny
sunny
but I get
sunny
null
Question updated because I worded myself poorly.
because your headElement after remove(0) is:
LinkedElement<String> headElement = new LinkedElement<String>("what's");//0
headElement.add("up!");//1
headElement.add("That's");//2
headElement.add("Mitch");//3
headElement.add("Jones!");//4
and then you remove(2) from result above: which is "That's"; //at index 2
so yo get:
LinkedElement<String> headElement = new LinkedElement<String>("what's");//0
headElement.add("up!");//1
headElement.add("Mitch");//2
headElement.add("Jones!");//3
Try to print after remove(0) and you can get what is happening!
Try this:
public LinkedElement<T> remove(int i) {
int iterator = i;
// Store current head element;
LinkedElement<T> tempNode = this;
// If head element itself is to be removed
if (iterator == 0) {
if (tempNode.link != null) {
tempNode.name = tempNode.link.name;
tempNode.link = tempNode.link.link;
}
if (tempNode.link == null) {
tempNode.name = null;
tempNode.link = null;
}
return tempNode;
// If the element is further down in the linkedlist
// iterate through list and invoke "remove" at the desired position inside
// the list
}
if (iterator > 0) {
iterator = iterator - 2;
return tempNode.link.remove(iterator);
}
return tempNode;
}
Might try the following
public class LinkedElement<T> {
private T value;
private LinkedElement<T> linkToNextElement;
public LinkedElement(T element) {
value = element;
linkToNextElement = null;
}
public static void main(String args[]) {
LinkedElement<String> head = new LinkedElement("a");
head.add("b");
head.add("c");
head.add("d");
head.add("e");
LinkedElement<String> newHead = head;
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(1)###");
newHead = head.remove(1);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(3)###");
newHead =head.remove(3);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(0)###");
newHead =head.remove(0);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(0)###");
newHead =head.remove(0);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(i)###");
newHead =head.remove(7);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
System.out.println("Head: value="+newHead.value+"\n");
System.out.println("###remove(0)###");
newHead =head.remove(0);
for (int i = 0; i <= 6; i++) {
System.out.println("list[" + i + "]=" + head.get(i));
}
//empty List
if(newHead == null)
{
System.out.println("Head: value= NULL : no value for emplty list" );
}
}
/**
* Returns the value of the i-th linked element, assuming the current element to
* be at index 0.
*
* #param i 0-based index of the element whose value to return.
* #return the i-th element's value, or {#code null} if there is no element with
* that index.
*/
public T get(int i) {
int counter = 0;
LinkedElement<T> currElement = this;
if (i == 0) {
return value;
}
while (counter < i) {
if (currElement.linkToNextElement != null) {
currElement = currElement.linkToNextElement;
} else {
return null;
}
counter++;
}
return currElement.value;
}
/**
* Adds a new linked element holding the given value at the end of the linked
* elements.
*
* #param newVal the new value.
*/
public void add(T newVal) {
if (linkToNextElement == null) {
linkToNextElement = new LinkedElement<T>(newVal);
} else {
linkToNextElement.add(newVal);
}
}
/**
* Removes the i-th element from the linked elements. If {#code i == 0}, this
* will effectively remove the head element. Thus, this method returns the
* linked element that is the new head element.
*
* #param i index of the element to remove.
* #return the new head element.
*/
public LinkedElement<T> remove(int i) {
int counter = 0;
LinkedElement<T> currElement = this;
LinkedElement<T> prevElement = null;
LinkedElement<T> nextElement = null;
if (i == 0) {
if (currElement.linkToNextElement != null) {
nextElement = currElement.linkToNextElement;
value = nextElement.value;
if (nextElement.linkToNextElement != null) {
linkToNextElement = nextElement.linkToNextElement;
} else {
linkToNextElement = null;
}
// ;
return nextElement;
} else {
value = null;
linkToNextElement = null;
}
return linkToNextElement;
}
while (counter < i) {
if (currElement.linkToNextElement != null) {
prevElement = currElement;
currElement = currElement.linkToNextElement;
} else {
return this;
}
counter++;
}
if (currElement.linkToNextElement != null) {
nextElement = currElement.linkToNextElement;
prevElement.linkToNextElement = nextElement;
}
// last element
else {
prevElement.linkToNextElement = null;
}
return this;
}
}
Output
list[0]=a
list[1]=b
list[2]=c
list[3]=d
list[4]=e
list[5]=null
list[6]=null
Head: value=a
###remove(1)###
list[0]=a
list[1]=c
list[2]=d
list[3]=e
list[4]=null
list[5]=null
list[6]=null
Head: value=a
###remove(3)###
list[0]=a
list[1]=c
list[2]=d
list[3]=null
list[4]=null
list[5]=null
list[6]=null
Head: value=a
###remove(0)###
list[0]=c
list[1]=d
list[2]=null
list[3]=null
list[4]=null
list[5]=null
list[6]=null
Head: value=c
###remove(0)###
list[0]=d
list[1]=null
list[2]=null
list[3]=null
list[4]=null
list[5]=null
list[6]=null
Head: value=d
###remove(7)###
list[0]=d
list[1]=null
list[2]=null
list[3]=null
list[4]=null
list[5]=null
list[6]=null
Head: value=d
###remove(0)###
list[0]=null
list[1]=null
list[2]=null
list[3]=null
list[4]=null
list[5]=null
list[6]=null
Head: value= NULL : no value for empty list
I have an assignment to complete a DoublyLinkList assignment and I am having some difficulty with two of the methods. I was given the code for MyList and MyAbstractList and was told to extend MyAbstractList with my DoublyLinkedList. I am not allowed to change MyList or MyAbstractList.
Here is the code for MyList I was provided:
public interface MyList<E extends Comparable<E>> {
/** Return true if this list contains no elements */
public boolean isEmpty();
/** Return the number of elements in this list */
public int size();
/** Add a new element at the proper point */
public void add(E e);
/** Clear the list */
public void clear();
/** Return true if this list contains the element */
public boolean contains(E e);
/** Return the element from this list at the specified index */
public E get(int index);
/** Return the first element in the list */
public E getFirst();
/** Return the last element in the list */
public E getLast();
/** Return the index of the first matching element in this list.
* Return -1 if no match. */
public int indexOf(E e);
/** Return the index of the last matching element in this list
* Return -1 if no match. */
public int lastIndexOf(E e);
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
public boolean remove(E e);
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
public boolean remove(int index);
/** Remove the first element in the list, return true if done, false if list is empty */
public boolean removeFirst();
/** Remove the Last element in the list, return true if done, false if list is empty */
public boolean removeLast();
/** Replace the element at the specified position in this list
* with the specified element and return true if done, false if index out of range. */
public boolean set(int index, E e);
}
and this was the code I was provided for MyAbstractList:
public abstract class MyAbstractList<E extends Comparable<E>> implements MyList<E> {
protected int size = 0; // The size of the list
/** Create a default list */
protected MyAbstractList() {
}
/** Create a list from an array of objects */
public MyAbstractList(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
#Override /** Return true if this list contains no elements */
public boolean isEmpty() {
return size == 0;
}
#Override /** Return the number of elements in this list */
public int size() {
return size;
}
}
Finally here is my code for MyDoublyLinkedList:
import java.util.ArrayList;
public class MyDoublyLinkedList<E extends Comparable<E>> extends MyAbstractList<E>
{
int size =0;
Node<E> head = null;
Node<E> current = null;
Node<E> tail = null;
public MyDoublyLinkedList() {
}
/** Create a list from an array of objects */
public MyDoublyLinkedList(E[] objects) {
super(objects);
}
#Override
public boolean isEmpty()
{
return size == 0;
}
#Override
public int size()
{
return size;
}
/** Add a new element at the proper point */
#Override
public void add(E e)
{
Node<E> newNode = new Node<E>(e);
if (tail == null) {
head = tail = newNode;
}
else //if (head != null)
{
tail.next = newNode;
tail = newNode;
}
size++;
}
#Override
public void clear()
{
size = 0;
head = tail = null;
}
#Override
public boolean contains(E e)
{
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (current.element.equals(e))
return true;
current = current.next;
}
return false;
}
#Override
public E get(int index)
{
if (index < 0 || index > size - 1)
return null;
Node<E> current = head;
for (int i = 0; i < index; i++)
current = current.next;
return current.element;
}
#Override
public E getFirst()
{
if (size == 0) {
return null;
}
else {
return head.element;
}
}
#Override
public E getLast()
{
if (size == 0) {
return null;
}
else {
return tail.element;
}
}
#Override
public int indexOf(E e)
{
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (current.element.equals(e))
return i;
current = current.next;
}
return -1;
}
#Override
public int lastIndexOf(E e)
{
int lastIndex = -1;
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (current.element.equals(e))
lastIndex = i;
current = current.next;
}
return lastIndex;
}
/** Remove the first occurrence of the element o from this list.
* Shift any subsequent elements to the left.
* Return true if the element is removed. */
#Override
public boolean remove(E e)
{
int index = indexOf(e);
if (index != -1) {
return remove(index);
} else {
return false;
}
}
/** Remove the element at the specified position in this list
* Shift any subsequent elements to the left.
* Return the element that was removed from the list. */
#Override
public boolean remove(int index)
{
if (index < 0 || index >= size) {
return false;
}
else if (index == 0) {
return removeFirst();
}
else if (index == size - 1) {
return removeLast();
}
else {
Node<E> previous = head;
for (int i = 1; i < index; i++) {
previous = previous.next;
}
Node<E> current = previous.next;
previous.next = current.next;
size--;
return true;
}
}
#Override
public boolean removeFirst()
{
if (size == 0) {
return false;
}
else {
Node<E> temp = head;
head = head.next;
size--;
if (head == null) {
tail = null;
}
return true;
}
}
#Override
public boolean removeLast()
{
if (size == 0) {
return false;
}
else if (size == 1) {
Node<E> temp = head;
head = tail = null;
size = 0;
return true;
}
else {
Node<E> current = head;
for (int i = 0; i < size - 2; i++) {
current = current.next;
}
Node<E> temp = tail;
tail = current;
tail.next = null;
size--;
return true;
}
}
#Override
public boolean set(int index, E e)
{
if (index < 0 || index > size - 1)
return false;
Node<E> current = head;
for (int i = 0; i < index; i++)
current = current.next;
E temp = current.element;
current.element = e;
return true;
}
#Override
public String toString()
{
StringBuilder result = new StringBuilder("[");
Node<E> current = head;
for (int i = 0; i < size; i++) {
result.append(current.element);
current = current.next;
if (current != null) {
result.append(", "); // Separate two elements with a comma
}
else {
result.append("]"); // Insert the closing ] in the string
}
}
return result.toString();
}
public String toStringBack()
{
StringBuilder result = new StringBuilder("[");
Node<E> current = tail;
for (int i = 0; i < size; i++) {
result.append(current.element);
current = current.previous;
if (current != null) {
result.append(", "); // Separate two elements with a comma
}
else {
result.append("]"); // Insert the closing ] in the string
}
}
return result.toString();
}
public void add(int index, E e)
{
if (index ==0) {
addFirst(e);// The new node is the only node in list
}
else if(index > size)
{
addLast(e);//The index location was bigger than size
}
else
{
Node<E> current = getAtIndex(index-1);
Node<E> temp = current.next;
current.next = new Node<E>(e);
(current.next).next = temp;
size++;
}
}
public void addFirst(E e)
{
Node<E> newNode = new Node<E>(e); // Create a new node
newNode.next = head; // link the new node with the head
head = newNode; // head points to the new node
size++; // Increase list size
if (tail == null) // the new node is the only node in list
tail = head;
}
public void addLast(E e)
{
Node<E> newNode = new Node<E>(e); // Create a new for element e
if (tail == null) {
head = tail = newNode; // The new node is the only node in list
}
else {
tail.next = newNode; // Link the new with the last node
tail = tail.next; // tail now points to the last node
}
size++;
}
protected Node<E> getAtIndex(int index)
{
int count;
if (index < 0 || index > size - 1)
return null;
Node<E> temp = null;
if(index <= (size/2))
{
count = -1;
temp = head;
while(++count <= index){
temp = temp.next;
}
}
else if (index > (size/2))
{
count = size;
temp = tail;
while(--count >= index){
temp = temp.previous; //--> this is Where the null pointer exception occurs
}
}
return temp;
}
private static class Node<E>{
E element;
Node<E> next;
Node<E> previous;
public Node(E element){
this.element = element;
next = null;
previous = null;
}
}
}
When I run the add(int index, E e) Method I receive a null pointer exception in the getAtIndext() method. I also have had issues getting the add(E e) Method to add properly when I change the current location. The methods are all as I am being required to use them. The use of iterators while they would be nice are not allowed. I am using Bluj as a compiler. Please let me know what questions you have.
Thank you
EDIT: I do know what a Null Pointer Exception is, I can not figure out why this is coming back as null. The Node "current" should point to the end, then go back in the list until it reaches the indexed location. This only happens when I try to add a node in the last half of the list. The error is thrown at temp = temp.previous;
The stack trace is:
java.lang.NullPointerException at MyDoublyLinkedList.getAtIndex(MyDoublyLinkedList.java:345) at MyDoublyLinkedList.add(MyDoublyLinkedList.java:289) at TestMyDoublyLinkedList.main(TestMyDoublyLinkedList.java:50)
Edit: I figured out the issue. The add() and getAtIndex functions are running properly. When I run the test the function that is throwing a Null Pointer Exception is throwing it at position 8. It cycles through the first few nodes fine, but dies at node 8
When inserting in the add() method, you never assign previous so it is null for all nodes.
I have a program that is supposed to allow me to create an RB Tree, but when I run it, I get the following error:
run:
Error: Main method not found in class mainrbt.MainRBT, please define the main method as:
public static void main(String[] args)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)
I've been trying to figure out if I can just put the "public static void main(String[] args)" somewhere inside so that I can go ahead and run it, but so far I have been unsuccessful.
Here is the MainRBT.java:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mainrbt;
import java.util.Random;
import java.util.Stack;
public class MainRBT {
/* *************************************************** *
* PRIVATE FIELDS *
* *************************************************** */
private RBTree tree;
private int size;
/* If during an insert() or delete() it is found that
* the key is present in the tree, keyFound will be true
* and prevValue will contain the previous value
* associated with the key before the update.
*/
private boolean keyFound;
private Object prevValue;
/* *************************************************** *
* PUBLIC INTERFACE *
* *************************************************** */
/*
* Constructs a new empty red-black tree.
*/
public MainRBT() {
tree = null;
size = 0;
}
/**
* Maps the key to the specified value in this red-black tree.
* Neither the key, nor the value can be
* <code>null</code>.
* #return the previous value to which the key was mapped,
* or <code>null</code> if the key did not have a previous
* mapping in the red-black tree.
*/
public synchronized Object put(/*Si*/String key, Object value) {
if (key == null || value == null)
throw new NullPointerException();
RBTree node = new RBTree();
node.key = key;
node.value = value;
keyFound = false;
tree = insert(node, tree);
if (keyFound)
return prevValue;
else {
size++;
return null;
}
}
/**
* Gets the object associated with the specified key in the red-black tree.
* #param args
* #return the value to which the key is mapped in the red-black tree, or
* <code>null</code> if the key is not mapped to any value in
* this red-black tree.
*/
public synchronized Object get(/*Si*/String key) {
RBTree t = tree;
int comp;
while (t != null && (comp = key.compareTo(t.key)) != 0)
if (comp < 0)
t = t.left;
else
t = t.right;
return t != null ? t.value : null;
}
/**
* Returns <code>true</code> if this red-black tree contains no mappings.
*/
public boolean isEmpty() {
return tree == null;
}
/**
* Removes the key (and its corresponding value) from this red-black tree.
* This method does nothing if the key is not in the red-black tree.
* #return the value to which the key had been mapped in this red-black tree,
* or <code>null</code> if the key did not have a mapping.
*/
public synchronized Object remove(/*Si*/String key) {
RBTree node = tree;
while (node != null) {
int comp = key.compareTo(node.key);
if (comp < 0)
node = node.left;
else if (comp > 0)
node = node.right;
else {
prevValue = node.value;
tree = delete(node, tree);
size--;
return prevValue;
}
}
return null;
}
/**
* Clear the red-black tree so that it contains no mappings.
*/
public synchronized void clear() {
tree = null;
size = 0;
}
/**
* Returns the number of keys in this red-black tree.
*/
public int size() {
return size;
}
/**
* Returns a string representation of this red-black tree.
* This routine is inefficient and primarily intended for
* debugging. To access the elements in the red-black tree in sorted order
* use the <code>keys()</code> and <code>elements()</code> methods.
* #see RedBlackTree#keys
* #see RedBlackTree#elements
*/
public synchronized String toString() {
StringBuffer strbuf = new StringBuffer();
strbuf.append("{");
if (tree != null)
strbuf.append(tree.toString());
if (strbuf.length() > 1)
strbuf.setLength(strbuf.length() - 2); // remove last ", "
strbuf.append("}");
return strbuf.toString();
}
/**
* Returns a string displaying the tree structure
* and the priority numbers.
*/
public synchronized String printDebug() {
StringBuffer strbuf = new StringBuffer();
String newline = System.getProperty("line.separator");
strbuf.append("size: " + size + newline);
if (tree != null)
tree.printDebug(0, strbuf);
return strbuf.toString();
}
public String printStat() {
StatStruct stat = new StatStruct();
collectStat(tree, 0, stat);
StringBuffer strbuf = new StringBuffer();
String newline = System.getProperty("line.separator");
strbuf.append("Aver depth: " +
(float) stat.totDepth / this.size + newline);
strbuf.append("Max depth: " + stat.maxDepth + newline);
return strbuf.toString();
}
/* *************************************************** *
* PRIVATE METHODS *
* *************************************************** */
/* Inserts a node into tree and returns the updated red-black tree */
private RBTree insert(RBTree node, RBTree tree) {
RBTree father = null, son = tree;
/* Insert the new node into the tree. */
while (son != null) {
father = son;
int comp = node.key.compareTo(son.key);
if (comp < 0)
son = son.left;
else if (comp > 0)
son = son.right;
else {
keyFound = true;
prevValue = son.value;
son.value = node.value;
return tree;
}
}
node.parent = father;
if (father == null)
tree = node;
else if (node.key.compareTo(father.key) < 0)
father.left = node;
else father.right = node;
/* Inforce the color invariants of the red-black tree. */
node.color = RBTree.RED;
while (node != tree && node.parent.color == RBTree.RED) {
if (node.parent == node.parent.parent.left) {
son = node.parent.parent.right;
if (son != null && son.color == RBTree.RED) {
node.parent.color = RBTree.BLACK;
son.color = RBTree.BLACK;
node = node.parent.parent;
node.color = RBTree.RED;
} else {
if (node == node.parent.right) {
node = node.parent;
tree = node.rotateLeft(tree);
}
node.parent.color = RBTree.BLACK;
node.parent.parent.color = RBTree.RED;
tree = node.parent.parent.rotateRight(tree);
}
} else {
son = node.parent.parent.left;
if (son != null && son.color == RBTree.RED) {
node.parent.color = RBTree.BLACK;
son.color = RBTree.BLACK;
node = node.parent.parent;
node.color = RBTree.RED;
} else {
if (node == node.parent.left) {
node = node.parent;
tree = node.rotateRight(tree);
}
node.parent.color = RBTree.BLACK;
node.parent.parent.color = RBTree.RED;
tree = node.parent.parent.rotateLeft(tree);
}
}
}
tree.color = RBTree.BLACK;
return tree;
}
/* Deletes a node from a red-black tree and
* returns the updated red-black tree.
*/
private RBTree delete(RBTree node, RBTree tree) {
RBTree x, y;
if (node.left == null || node.right == null)
y = node;
else
y = node.successorGet();
if (y.left != null)
x = y.left;
else
x = y.right;
if (x != null)
x.parent = y.parent;
if (y.parent == null)
tree = x;
else if (y == y.parent.left)
y.parent.left = x;
else
y.parent.right = x;
if (y != node) {
node.key = y.key;
node.value = y.value;
}
/* If the node to be removed is BLACK,
* restore the red-black tree invariants.
* The color of a null leaf is BLACK.
*/
if (y.color == RBTree.BLACK) {
RBTree father = y.parent;
while (x != tree && (x == null || x.color == RBTree.BLACK)) {
if (x == father.left) {
RBTree w = father.right;
if (w == null)
x = tree;
else {
if (w.color == RBTree.RED) {
w.color = RBTree.BLACK;
father.color = RBTree.RED;
tree = father.rotateLeft(tree);
continue;
}
if ((w.left == null || w.left.color == RBTree.BLACK) &&
(w.right == null || w.right.color == RBTree.BLACK)) {
w.color = RBTree.RED;
x = father;
father = x.parent;
}
else {
if (w.right == null || w.right.color == RBTree.BLACK) {
if (w.left != null) {
w.left.color = RBTree.BLACK;
w.color = RBTree.RED;
tree = w.rotateRight(tree);
w = father.right;
}
}
w.color = father.color;
father.color = RBTree.BLACK;
if (w.right != null)
w.right.color = RBTree.BLACK;
tree = father.rotateLeft(tree);
x = tree;
}
}
} else {
RBTree w = father.left;
if (w == null)
x = tree;
else {
if (w.color == RBTree.RED) {
w.color = RBTree.BLACK;
father.color = RBTree.RED;
tree = father.rotateRight(tree);
continue;
}
if ((w.right == null || w.right.color == RBTree.BLACK) &&
(w.left == null || w.left.color == RBTree.BLACK)) {
w.color = RBTree.RED;
x = father;
father = x.parent;
}
else {
if (w.left == null || w.left.color == RBTree.BLACK) {
if (w.right != null) {
w.right.color = RBTree.BLACK;
w.color = RBTree.RED;
tree = w.rotateLeft(tree);
w = father.left;
}
}
w.color = father.color;
father.color = RBTree.BLACK;
if (w.left != null)
w.left.color = RBTree.BLACK;
tree = father.rotateRight(tree);
x = tree;
}
}
}
}
if (x != null)
x.color = RBTree.BLACK;
}
return tree;
}
private class StatStruct {
int totDepth = 0;
int maxDepth = 0;
}
private void collectStat(RBTree t, int depth, StatStruct stat) {
if (t == null)
return;
else {
if (depth > stat.maxDepth)
stat.maxDepth = depth;
stat.totDepth += depth;
collectStat(t.left, depth + 1, stat);
collectStat(t.right, depth + 1, stat);
}
}
}
In addition, here is my RBTree.java file, in case it is also relevant to this problem:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mainrbt;
/**
*
* #author Owner
*/
public class RBTree {
public static final short BLACK = 0;
public static final short RED = 1;
short color;
RBTree left, right, parent;
/*Si*/String key;
Object value;
/* Rotate this tree to the left, update parent,
* and return the root.
*/
final RBTree rotateLeft(RBTree root) {
RBTree temp = right;
right = temp.left;
if (temp.left != null)
temp.left.parent = this;
temp.parent = parent;
if (parent == null)
root = temp;
else
if (this == parent.left)
parent.left = temp;
else
parent.right = temp;
temp.left = this;
parent = temp;
return root;
}
/* Rotate this tree to the right, update parent,
* and return the root.
*/
final RBTree rotateRight(RBTree root) {
RBTree temp = left;
left = temp.right;
if (temp.right != null)
temp.right.parent = this;
temp.parent = parent;
if (parent == null)
root = temp;
else
if (this == parent.right)
parent.right = temp;
else
parent.left = temp;
temp.right = this;
parent = temp;
return root;
}
/* Get the successor of this tree.
*/
final RBTree successorGet() {
RBTree temp, p;
if (right != null) {
temp = right;
while (temp.left != null)
temp = temp.left;
}
else {
temp = this;
p = parent;
while (p != null && temp == p.right) {
temp = p;
p = p.parent;
}
}
return temp;
}
public String toString() {
StringBuffer strbuf = new StringBuffer();
if (left != null)
strbuf.append(left.toString());
strbuf.append(key + "=" + value + ", ");
if (right != null)
strbuf.append(right.toString());
return strbuf.toString();
}
/* Print in sorted order, displaying the tree structure
* and the node colors.
*/
void printDebug(int level, StringBuffer strbuf) {
String newline = System.getProperty("line.separator");
if (left != null)
left.printDebug(level + 1, strbuf);
for (int i = 0; i < level; i++)
strbuf.append(" ");
if (color == RBTree.BLACK)
strbuf.append("BLACK, " + value + ": " + key + newline);
else
strbuf.append("RED, " + value + ": " + key + newline);
if (right != null)
right.printDebug(level + 1, strbuf);
}
}
If anyone knows how to fix this error, please let me know.
Which ever class needs to run first is the one you put that method in.
Put main method into the class which you want to run your codes first. Main method just like a entrance of your project.
I am going over my old test from Data Structures, and I cannot figure out how to implement the printtree(int level) method in my Tree class. I am restricted to using this structure. I cannot figure out an implementation to use without root.right or root.left, this is very frustrating.
/*
Exam 2. Problem 2. 03/09/2012
*/
import java.util.List;
import java.util.ArrayList;
/**
A tree in which each node has an arbitrary number of children.
*/
public class Tree
{
private Node root;
class Node
{
public Object data;
public List<Node> children;
/**
Computes the size of the subtree whose root is this node.
#return the number of nodes in the subtree
*/
public int size()
{
int sum = 0;
for (Node child : children) { sum = sum + child.size(); }
return 1 + sum;
}
public int leaves() {
int count = 0;
for (Node child : children) {
if (child.size() == 1) {
count = count + 1;
} else {
count = count + child.leaves();
}
}
if (count == 0) {
count = count + 1;
}
return count;
}
public String printTree(int level) {
String S = "";
S += root.data + " (level:" + level + ") ";
if (root != null) {
return S;
}
if (root.children != null) {
S += root.printTree(level + 1);
}
return S;
}
}
/**
Constructs an empty tree.
*/
public Tree()
{
root = null;
}
/**
Constructs a tree with one node and no children.
#param rootData the data for the root
*/
public Tree(Object rootData)
{
root = new Node();
root.data = rootData;
root.children = new ArrayList<Node>();
}
/**
Adds a subtree as the last child of the root.
*/
public void addSubtree(Tree subtree)
{
root.children.add(subtree.root);
}
/**
Computes the size of this tree.
#return the number of nodes in the tree
*/
public int size()
{
if (root == null) { return 0; }
else { return root.size(); }
}
public int leaves() {
Node newNode = root;
if (root == null) { return 0; }
else { return root.leaves(); }
}
public String printTree() {
return root.children.printTree(0);
}
}
you just need to change 3 things:
Change root to this every where in the printTree(int level) method
The placement of if(this == null) should be checked before anything else
Use a for loop to print all of the children
public String printTree(int level) {
String S = "";
// notice the change to '=='
if (this == null)
return S;
S += this.data + " (level:" + level + ") ";
// notice the for loop
if( this.children != null)
for(Node child : this.children)
S += child.printTree(level + 1);
return S;
}
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);
}
}