Max heap of nodes java - java

I currently need to implement a max heap of nodes where my node class keeps track of the data, the parent and then the left and right child. My insert method for max heap is taking forever to fill with an array of 100 strings. Here is my code: `
public void insert(String name) {
MyNode node = new MyNode(name);
if (root ==null) {
root = node;
}
else {
MyNode parent = findSpot(root);
if(parent.lChild==null) {
parent.lChild=node;
node.setParent(parent);
}
else {
parent.rChild=node;
node.setParent(parent);
}
}
}
public MyNode findSpot(MyNode curr) {
if (curr.lChild == null) {
return curr;
}
else if (curr.rChild==null) {
return curr;
}
else {
if (findSpot(curr.lChild).findHeight(root, curr, 1) > findSpot(curr.rChild).findHeight(root, curr, 1)) {
return findSpot(curr.lChild);
}
else {
return findSpot(curr.rChild);
}
}
}`
If anyone code offer suggestions or tell me whats wrong that'd be greatly appreciated.

If you want to see why your findSpot function is taking so long, add a line at the beginning that outputs "findSpot <node>", where is the details of the node being searched. You'll find that the recursive algorithm is being called many times. And it looks like findHeight is also being called quite often. I'm not certain, but it looks like you're doing an exhaustive tree search on every insertion.
Binary heaps must maintain the Shape property: it is a complete binary tree except possibly the bottom row, which is left-filled. Because of that, if you know how many nodes are in your heap, you can easily find the insertion spot for the next node. Consider this heap:
1
2 3
4 5 6
There are 6 nodes in the heap. Whenever there are 6 nodes in a heap, the tree will look like this and the insertion spot for the next node will be the right child of the far right node (3 in this case).
The interesting thing is that the binary representation of the node number tells us where that node is. For example, 6 in binary is 110. Lop off the first digit, 1, and you're left with 10. Now, starting at the root and taking the next digit in the number, go left if the digit is 0, and right if the digit is 1. Then take the next digit and do the same thing. Repeat until you run out of digits.
In the case of 6, we'd go right from the root to node 3, and then left to node 6.
When you're adding a new node, increment the count and follow the procedure above to locate the insertion spot. 7 is 111 in binary. You lop off the high bit, leaving 11. Then, starting at the root you go right, and the insertion spot is the right child of node 3.
Of course, once you've placed the node in the tree to satisfy the shape property, you have to do the standard re-heapify to adjust the nodes in the tree so that the heap property is maintained.

Related

Print all possible diameters of Binary Tree?

I know how to calculate the diameter of tree but I want to print all possible diameters of tree. Taking the below example:-
1
/ \
2 3
/ / \
4 5 6
All Possible diameters in above tree are:-
First: 4 2 1 3 5
Second: 4 2 1 3 6
Any help regarding approach will very helpful.
I assume you mean all possible paths of maximal length from one leaf to another?
Recursion may be your best bet - in pseudocode something like:
path(startNode, endNode) {
if startNode = endNode return;
for each possible next node n {
add n to your path;
path(n, endNode);
}
}
You could call this for each pair of leaves then throwaway any non-maximal length paths, or perhaps choose which leaves to call this on in a bit more of a smart way, which I would leave up to you
How is this done in graphs:
Run BFS from any node n to find most distant node (from that node) n'
Run BFS from node n' to his most distant node n''
The path from n' to n'' is the tree diameter
So, looking at a tree (which can be unrolled into a graph):
A diameter path goes from any leaf on the lowest level in the left sub-tree to any leaf on the lowest level in the right sub-tree.
Now, since you don't don't magically know which 2 nodes are the end nodes of a diameter, and you only have parent-to-child links, the above algorithm wont work, per se. However, you can use the analogy to build one that works on trees instead of graphs.
OK, here is some quick code you can use (it may not be optimal, but it works)
public class BinarySearchTree {
...
public Iterable<T> diameter() {
if (this.root == null) {
return null;
}
Deque<T> diameterLeftPart = new ArrayDeque<T>();
Deque<T> diameterRightPart = new ArrayDeque<T>();
diameter(this.root.left, diameterLeftPart);
diameter(this.root.right, diameterRightPart);
Deque<T> diameter = new ArrayDeque<T>();
for (Iterator<T> it = diameterLeftPart.iterator(); it.hasNext();) {
diameter.offerLast(it.next());
}
diameter.offerLast(this.root.item);
for (Iterator<T> it = diameterRightPart.descendingIterator(); it.hasNext();) {
diameter.offerLast(it.next());
}
return diameter;
}
private void diameter(Node node, Deque<T> diameter) {
if (node == null) {
return;
}
Deque<T> leftPart = new ArrayDeque<T>();
Deque<T> rightPart = new ArrayDeque<T>();
diameter(node.left, leftPart);
diameter(node.right, rightPart);
if (leftPart.size() > rightPart.size()) {
diameter.addAll(leftPart);
} else {
diameter.addAll(rightPart);
}
diameter.offerLast(node.item);
}
...
}
And the runner class:
public class TreeDiameter {
public static void main(String[] args) {
Tree<Integer> tree = new BinarySearchTree<Integer>();
tree.add(5);
tree.add(2);
tree.add(8);
tree.add(1);
tree.add(3);
tree.add(7);
tree.add(9);
tree.add(4);
tree.add(6);
for (Integer diameterNode : tree.diameter()) {
System.out.print(diameterNode + " ");
}
}
}
With the following output:
4 3 2 5 8 7 6
Quick explanation:
We know that the root is the integral part of the diameter path.
So, we want to get the longest path in the left sub-tree and the longest path in the right sub-tree.
Glued together, they create a diameter.
Using recursive calls diameter(node.left, leftPart) and diameter(node.right, rightPart), leftPart and rightPart contain longest paths in left and right sub-trees, respectively.
Simply comparing their sizes gives us the indication which one we will use in constructing the diameter for one level up the tree.
So, to sum up:
Recursion first goes all the way down to the tree and returns the longest path in that sub-tree, passing it upwards to its parent, all the way up to the root.

making a Binary Search Tree from a Sorted Doubly Linked List

Hey guys So I am studying programming interview questions and I got stuck in this one.
I am trying to do this recursively but I don't know where to start.
This is the algorithm I have so far:
makeTree(head, tail){
nodeMid = list/2
root = nodeMid
root.left = makeTree(head, nodeMid)
root.right = makeTree(nodeMid, tail)
Do I have the right idea? any input is highly appreciated. Thanks!
Below are some important points:
Get the Middle of the linked list and make it root.
Recursively do same for left half and right half.
Get the middle of left half and make it left child of the root
created in step 1.
Get the middle of right half and make it right child of the
root created in step 1.
Time complexity: O(nLogn) where n is the number of nodes in Linked List.
The major problem I see immediately and forgive me if I am wrong you are not changing the location of the list for each node.
each time you recursively call
makeTree(head, tail){
nodeMid = list/2;
as far as I can see inside the loop you do not change which part of the list goes with the recursive call. ie
you have an array of ints
myints which has (0,1,2,3,4,5,6,7,8,9)
every time the recursion is called it will infinitely fill the binary tree with the number at list/2
you need to change the value of nodeMid with each call, use the head/tail variables you are sending.
you do not want to keep resetting the root node either. you should be using the "this" operator to set the value of the current node you are looking at.
start being the start of the portion of the array you are looking at
and end being the end of the portion.
the recursive calls would be so.
you also need to add in the boundaries of the recursion
Using a BST with nodes when you create a new node in the tree the left and right nodes would be set to null to start with. you need to create a new node and call the recursion.
Node makeTree(int head, int tail){
nodeMid = (head+tail)/2;
this = new Node();
if(head < nodeMid-1)
{
this.left = makeTree(head, nodeMid-1);
}
if(nodeMid < tail)
{
this.right = makeTree(nodeMid, tail);
}
this.setValue(list[nodeMid]);
return this;
}
after all the recursion is done you need to set the value of the current node and return that node for the creation.
this will recursively turn a sorted array into a binary search tree. simply put in the proper list coding for your doubly linked list.
To start the recursion
root = makeTree(0, list.length());
Logic
1) Get the Middle of the linked list and make it root.
2) Recursively do same for left half and right half.
a) Get the middle of left half and make it left child of the root
created in step 1.
b) Get the middle of right half and make it right child of the
root created in step 1.
Code
public Node bstToDll(Node root ){
if(root!=null){
Node lefthead = bstToDll(root.left); // traverse down to left
Node righthead = bstToDll(root.right); // traverse down to right
Node temp = null;
/*
* lefthead represents head of link list created in left of node
* righthead represents head of link list created in right
* travel to end of left link list and add the current node in end
*/
if(lefthead != null) {
temp = lefthead;
while(temp.next != null){
temp = temp.next;
}
temp.next = root;
}else{
lefthead = root;
}
root.prev = temp;
/*
*set the next node of current root to right head of right list
*/
if(righthead != null){
root.next = righthead;
righthead.prev = root;
}else{
righthead = root;
}
return lefthead;// return left head as the head of the list added with current node
}
return null;
}
But this is not the most optimized way since the time complexity is O(nlogn). For a better optimized solution take a look at http://www.geeksforgeeks.org/sorted-linked-list-to-balanced-bst/

String heap not inserting properly

I've been working on my assignment which is to create a heap of strings, and do various functions on it. I'm now testing my code to see if it's inserting properly, and it's not. I'm testing the words: Golf, Bravo, Hotel, Alpha, Delta, Echo, Charlie, Foxtrot which would insert them alphabetically however when I print my heap I end up with:
Alpha
Bravo Charlie
Foxtrot Delta Hotel Echo
Golf
Here is the code that I have written:
public boolean insert(String key) {
if(currentSize == maxSize) {
return false;
}
Node newNode = new Node(key);
heapArray[currentSize] = newNode;
trickleUp(currentSize++);
return true;
}
public void trickleUp(int index) {
int parent = (index - 1) / 2;
Node bottom = heapArray[index];
while(index > 0 && heapArray[parent].getKey().compareTo(bottom.getKey()) > 0) {
heapArray[index] = heapArray[parent];
index = parent;
parent = (parent - 1) / 2;
}
heapArray[index] = bottom;
}
EDIT: After doing a quick search and finding another source code for a Heap, and testing it I was given the same output. Is there a reason why this is not being added alphabetically?
The behaviour you show in your printout is correct for a min heap, see:
http://en.wikipedia.org/wiki/Heap_(data_structure)
From the introductory paragraph (emphasis added):
Either the keys of parent nodes are always greater than or equal to those of the children and the highest key is in the root node (this kind of heap is called max heap) or the keys of parent nodes are less than or equal to those of the children and the lowest key is in the root node (min heap).
From the second paragraph (emphasis added):
there is no implied ordering between siblings or cousins and no implied sequence for an in-order traversal (as there would be in, e.g., a binary search tree). The heap relation mentioned above applies only between nodes and their immediate parents.
Your heap appears correctly ordered, in that each node only has children that are greater than it, alphabetically.

Restore heap condition throughout the entire heap

I'm trying to answer the following programming question:
In the heap.java program, the insert() method inserts a new node in the heap and ensures the heap condition is preserved. Write a toss() method that places a new node in the heap array without attempting to maintain the heap condition. (Perhaps each new item can simply be placed at the end of the array.) Then write a restoreHeap() method that restores the heap condition throughout the entire heap. Using toss() repeatedly followed by a single restoreHeap() is more efficient than using insert() repeatedly when a large amount of data must be inserted at one time. See the description of heapsort for clues. To test your program, insert a few items, toss in some more, and then restore the heap.
I've written the code for the toss function which successfully inserts the node at the end and doesn't modify the heap condition. I'm having problems with the restoreHeap function though and I can't wrap my head around it. I've included the two functions below.
The full code of heap.java is here (includes toss() and restoreHeap() )
toss() - I based this off the insert function
public boolean toss(int key)
{
if(currentSize==maxSize)
return false;
Node newNode = new Node(key);
heapArray[currentSize] = newNode;
currentSize++;
return true;
} // end toss()
restoreHeap() - I based this off the trickleUp function and I'm getting a StackOverflowError.
public void restoreHeap(int index)
{
int parent = (index-1) / 2;
Node bottom = heapArray[index];
while( index > 0 &&
heapArray[parent].getKey() < bottom.getKey() )
{
heapArray[index] = heapArray[parent]; // move it down
index = parent;
parent = (parent-1) / 2;
} // end while
heapArray[index] = bottom;
while(index != 0)
{
restoreHeap(parent++);
}
} // end restoreHeap()
Any ideas? Help appreciated.
I'll give it a shot. Here is a way to do what you asked with some explanation.
Since you know that half of all nodes in a heap are leafs and a leaf, by itself, is a valid heap, you only have to run through the other half of the nodes to make sure they also are valid. If we do this from the bottom and up, we can maintain a valid heap structure "below" as we go up through the heap. This can easily be accomplished by a for loop:
public void rebuildHeap()
{
int half = heapArray.length / 2;
for(int i = half; i >= 0; i--)
restoreHeap(i);
}
How is restoreHeap implemented then?
It's supposed to check the node at index against its children to see if it needs to relocate the node. Because we make sure that the trees below the index node are heaps, we only have to move the index node to the right position. Hence we move it down in the tree.
First we need to locate the children. Since each row in the three have twice as many nodes as the row before, the children can be located like this:
private void restoreHeap(int index)
{
int leftChild = (index * 2) + 1; //+1 because arrays start at 0
int rightChild = leftChild +1;
...
Now you just have to compare the childrens value against your index nodes value. If a child have a bigger value you need to swap the index node with the child node. If both children have a bigger value, you need to swap with the child with the biggest value of the two (to maintain the heap structure after the swap). When the nodes have been swapped you need to call the method again to see if you need to move the index node further down the tree.
...
int biggest = index;
if(leftChild < currentSize && heapArray[leftChild].getKey() > heapArray[index].getKey())
biggest = leftChild; //LeftChild is bigger
if(rightChild < currentSize && heapArray[rightChild].getKey() > heapArray[biggest].getKey())
biggest = rightChild; //RightChild is bigger than both leftChild and the index node
if(biggest != index) //If a swap is needed
{
//Swap
Node swapper = heapArray[biggest];
heapArray[biggest] = heapArray[index];
heapArray[index] = swapper;
restoreHeap(biggest);
}
}

Attempting to remove an Element at specific location in user-defined Doubly Linked List

This is from an old homework problem, that I already turned in, but I wasn't able to figure it out. I'm trying to remove an element from my LinkedList at a specific index using my user-defined class. Below is the pseudo code I'm working off of, but it doesn't have the same parameters as mine so I tried modifying it, but had an issue. I'm a programming noob (roughly 6 months of experience), just FYI. I understand ArrayLists just fine, but LinkedLists have been giving me trouble.
/*
* Remove the nth element in the list. The first element is element 1.
* Return the removed element to the caller.
function remove(List list, Node node)
if node.prev == null
list.firstNode := node.next
else
node.prev.next := node.next
if node.next == null
list.lastNode := node.prev
else
node.next.prev := node.prev
destroy node
*/
My method asks the user to enter an index position to delete. Because an int and LinkEntry are different types, naturally I'm having issues. I don't know how to incorporate the int that is passed through the parameter.
public void remove(int n)
{
LinkEntry<E> remove_this = new LinkEntry<E>();
remove_this.element = n;
for (remove_this = head; remove_this != null; remove_this = remove_this.next)
{
//removes the head if list is only 1 item long
if (head.next == null)
head = remove_this.next;
else
//sets previous element to the next element
remove_this.previous.next = remove_this.next;
//if nothing comes after remove_this, then remove the tail element
if (remove_this.next == null)
tail = remove_this.previous;
else
//sets next previous element to current previous element
remove_this.next.previous = remove_this.previous;
}
}
If you know of anywhere that gives another example that is more similar to what I'm trying to solve I would really appreciate it. I've looked through my text and online, but no luck.
You should set a counter to zero, browse your linked list from its first element (apparently named "head"), and increment the counter until its equal to n (or you reached the end of the list).
When counter equals to n, you must connect previous entry to next, and next to previous (so it deconnects the Nth). You also have to take care of special cases, when n=1 (you're supposed to delete "head" entry, that is to say set head to head.next), when next is null (n = list length), and when n negative or greater than list length.
When I learned this in galaxy far, far away ... it helped me to paint it on paper. Something like this:
You have
A B C
next *------>*------>*---->NULL
prev NULL<---*<------*-------*
and you want
A C
next *------>*---->NULL
prev NULL<---*<------*
So if you find B, you know what to do. But how to find B? B is the second element in our example above, so we'll be given a "1" in zero-based lists or a "2" in one-based lists.
A typical scenario would be to hold a reference to the first element of the list. This is often referred to as the "head". Now you would start with that head and follow its next-pointer. What do you get? The second element in the list. In our example that would already be our "B". Notice, that we followed next 1 time ... now assume we were to delete C. We got index 2 ( or one-based: 3) , we startet with head, followed next 1 time and got B. 1<2 so follow next again. Notice that we have to follow B's next instead of "head"'s So if using a loop, we'll have to use some sort of local var. Now we have the 2nd Element, which is C and remove it. Notice that C's "next" is null. So we are done in that direction.

Categories