I'm working on my assignment, which is to read from a text file, store the first 10 words in a heap. Then continue to read from the text file and if the word is less than the root of the heap, to replace it and re-heap the entire heap. My code seems to be working for the most part however I am running into a few problems.
Some words even though they are less than the root are not being swapped
Duplicate words
I am supposed to end up with a heap containing the words abandoning abandons
abased
abash
abashed
abashes
abasing
abate
abatement
abbe
However I get the words, abashes
abashed abash
abased abandons abandoning bewilderedly
abandoning armful abandoning
Here is my code so far:
public static void readFile() {
BufferedReader reader;
String inputLine;
int counter = 0;
try {
reader = new BufferedReader(new FileReader(".\\src\\dictionary.txt"));
while((inputLine = reader.readLine()) != null) {
if(counter < 10) {
heap.insert(inputLine);
counter++;
}
if(inputLine.compareTo(heap.find(0)) < 0) {
heap.change(0, inputLine);
}
}
} catch (IOException e) {
System.out.println("Error: " + e);
}
}
public boolean insert(String value) {
if(currentSize == maxSize) { return false; }
Node newNode = new Node(value);
heap[currentSize] = newNode;
trickleUp(currentSize++);
return true;
}
public void trickleUp(int index) {
int parent = (index - 1) / 2;
Node bottom = heap[index];
while(index > 0 && heap[parent].getData().compareTo(bottom.getData()) < 0) {
heap[index] = heap[parent];
index = parent;
parent = (parent - 1) / 2;
}
heap[index] = bottom;
}
public void trickleDown(int index) {
int largerChild;
Node top = heap[index];
while(index < currentSize / 2) {
int leftChild = 2 * index + 1;
int rightChild = index + 1;
if(rightChild < currentSize && heap[leftChild].getData().compareTo(heap[rightChild].getData()) < 0) {
largerChild = rightChild;
} else {
largerChild = leftChild;
}
if(top.getData().compareTo(heap[largerChild].getData()) > 0) {
break;
}
heap[index] = heap[largerChild];
index = largerChild;
}
heap[index] = top;
}
public boolean change(int index, String newValue) {
if(index < 0 || index >= currentSize) { return false; }
String oldValue = heap[index].getData();
heap[index].setData(newValue);
if(oldValue.compareTo(newValue) < 0) {
trickleUp(index);
} else {
trickleDown(index);
}
return true;
}
You won't get binary tree if you use such indexing:
int leftChild = 2 * index + 1;
int rightChild = index + 1;
I think you meant to write this:
int leftChild = 2 * index + 1;
int rightChild = 2 * index + 2;
So the tree will look like this
0
/ \
1 2
/ \ / \
3 4 5 6
/ \
7 8 ... and so on
As for duplicate elements as far as I know heap can contain duplicates and does not support duplicate removal. For example this is a valid heap of numbers
10
/ \
9 8
/ \ / \
5 7 7 6
Related
Can anyone help me.
If i have tree, the inorder traversal AVL Tree is
-1 0 1 2 5 6 9 10 11 12
then i want to have method sumGreater(n)
if
sumGreater(6) = 9 + 10 + 11 + 12 = 42
I tried to modified this.
https://www.geeksforgeeks.org/count-greater-nodes-in-avl-tree/
but it wont work.
Node rightRotate(Node y, int key) {
Node x = y.left;
Node T2 = x.right;
x.right = y;
y.left = T2;
y.height = max(height(y.left), height(y.right)) + 1;
x.height = max(height(x.left), height(x.right)) + 1;
int val = (T2 != null) ? T2.desc : -1;
y.desc = y.desc - (x.desc + key) + (val + key); // modified
x.desc = x.desc - (val + key) + (y.desc + key); // modified
return x;
}
int SumGreater(Node root, int x) {
int res = 0;
while (root != null) {
int desc = (root.right != null) ? root.right.desc : -1;
if (root.key > x) {
res = res + desc + 1 + 1;
root = root.left;
} else if (root.key < x) {
root = root.right;
} else {
res = res + desc + 1;
break;
}
}
return res;
}
this still count node not sum of node.
Can anyone help me with O(logN) time complexity
Please help me
corrected code and help
Does desc also represent the number of descendant nodes for a node? Then it is unnecessary to take it into account when you want to count the sum of value of nodes greater than n. You should sum their keys. Besides, since your function doesn't modify the tree, there is no need to consider rotation.
Here is my advice code in recursion.
int SumGreater(Node root, int x) {
int res = 0;
while (root != null) {
if (root.key > x) {
res += root.key;
res += SumGreater(root.right, x);
root = root.left;
} else {
root = root.right;
}
}
return res;
}
I require an implementation of a Priority queue that allows decrease priority operation to allow for an efficient implementation for Prim's and Dijkstra's algorithm.
I've coded up a minHeap implementation using a HashMap to store the indices of elements in my heap.
The problem I'm working on requires the computation of the total weight of the minimum spanning tree obtained by using Prim's algorithm. While my implementation works for most test cases upto 200 nodes, I'm still getting the incorrect output for many larger test cases.
It is my understanding that such minheap based implementations of Priority queues using HashMaps are common, if I am wrong in my assumption, please provide the more suitable approach to this problem.
I've been trying to debug my code for 2 days now and it seems the only way to fix it would be to compare it with a correctly functioning implementation.
Therefore, can someone please share such a PriorityQueue implementation using HashMap in java.
Even though I've tried a lot of test cases and for all the ones I can trace on my own(upto 30 nodes) I've gotten correct answers so far, but if there are some specific boundary test cases that could help me identify the problem, that too will be great.
Here is my code, I understand debugging it will be time consuming for anyone else, but if there is something obvious I've missed and someone with more expertise can point out the mistake, that would be most appreciated.
import java.util.HashMap;
import java.util.NoSuchElementException;
public class Heap<Key extends Comparable<Key>> {
private Key[] heap;
private int maxN, n;
private HashMap<Key, Integer> map;
#SuppressWarnings("unchecked")
public Heap(int maxN) {
if(maxN < 0 ) throw new IllegalArgumentException();
this.maxN = maxN;
n = 0;
heap = (Key[]) new Comparable[maxN];
map = new HashMap<>(maxN);
}
boolean isEmpty() {
return n == 0;
}
boolean insert(Key e) {
if(n +1 > maxN) throw new IllegalArgumentException("maximum capacity reached " + maxN);
heap[n] = e;
map.put(e,n);
int i = n++;
while ( (i+1)/2 - 1 >= 0){
if ( e.compareTo(heap[(i+1)/2 - 1]) < 0 ) {
swap(i, (i+1)/2 - 1);
i = (i+1)/2 - 1;
}
else
break;
}
return true;
}
Key extractMin() {
if(n == 0) throw new NoSuchElementException("Priority queue underflow ");
Key min = heap[0];
swap(0, n-1);
map.remove(min);
n--;
int j = 0, s;
while(j <= (n/2)-1){
if(j == (n/2)-1 && n == (j+1)*2 )
s = (j+1)*2 - 1;
else
s = heap[(j+1)*2 - 1].compareTo(heap[(j+1)*2]) < 0 ? (j+1)*2 - 1 : (j+1)*2;
if(heap[j].compareTo(heap[s]) > 0 ){
swap(j, s);
j = s;
}
else break;
}
return min;
}
Key delete(Key e){
if(!map.containsKey(e)) throw new NoSuchElementException(e+"does not exist ");
int j = map.get(e), s;
Key del = e;
swap(j, n-1);
map.remove(e);
n--;
while( j <= n/2 - 1){
if(j == (n/2)-1 && n == (j+1)*2)
s = (j+1)*2 - 1;
else
s = heap[(j+1)*2 - 1].compareTo(heap[(j+1)*2]) < 0 ? (j+1)*2 - 1 : (j+1)*2;
if(heap[j].compareTo(heap[s]) > 0 ){
swap(j, s);
j = s;
}
else break;
}
return del;
}
boolean decreasePriority(Key e){
if(n == 0)
return insert(e);
if(map.containsKey(e))
delete(e);
return insert(e);
}
private void swap(int i, int j) {
Key t = heap[i];
heap[i] = heap[j];
heap[j] = t;
map.replace(heap[i], i);
map.replace(heap[j], j);
}
#Override
public String toString() {
String res = "[";
int i;
for (i = 0; i < n-1; i++){
res += heap[i] + ", ";
}
res += heap[i]+"]";
return res;
}
}
I think the problem is in your delete method. Your code does this:
swap item to be removed with the last item in the heap
reduce heap count
push the new item down the heap
You're making the assumption that heap[j] < heap[n-1]. That's not a valid assumption. Consider this heap:
1
6 2
7 8 3
If you delete the node with value 7, the value 3 replaces it:
1
6 2
3 8
You now have to move it up the tree to make a valid heap:
1
3 2
6 8
The key here is that if the item you're replacing is in a different subtree than the last item in the heap, it's possible that the replacement node will be smaller than the parent of the replaced node.
If you're removing an item from the middle of the heap, you swap the item with the last, then you have to check whether the replacement node moves up or down.
Something you should consider, though, is that to change an item's priority, you don't have to delete and re-add. All you have to do is change the priority and then adjust the item's position appropriately: move up or down to put it in its new position.
The delete method was incorrect, I was using the same procedure for arbitrary deletes as for extractMin, which did not take into account the fact that the element I replace the key to be deleted with could possibly go both up or down the heap. Using swim() and sink() methods I have rectified this error. Also to change priority deletion and insertion are not required, and a simple call to both swim and sink is sufficient.(only swim if only decreasing priority and only sink if only increasing).
import java.util.HashMap;
import java.util.NoSuchElementException;
public class Heap<Key extends Comparable<Key>> {
private Key[] heap;
private int maxN, n;
private HashMap<Key, Integer> map;
#SuppressWarnings("unchecked")
public Heap(int maxN) {
if(maxN < 0 ) throw new IllegalArgumentException();
this.maxN = maxN;
n = 0;
heap = (Key[]) new Comparable[maxN];
map = new HashMap<>(maxN);
}
boolean isEmpty() {
return n == 0;
}
boolean insert(Key e) {
if(n +1 > maxN) throw new IllegalArgumentException("maximum capacity reached " + maxN);
heap[n] = e;
map.put(e,n);
int i = n++;
swim(i);
return true;
}
Key extractMin() {
if(n == 0) throw new NoSuchElementException("Priority queue underflow ");
Key min = heap[0];
swap(0, n-1);
map.remove(min);
n--;
sink(0);
return min;
}
void delete(Key e){
if(!map.containsKey(e)) throw new NoSuchElementException(e+" does not exist ");
int j = map.get(e);
swap(j, n-1);
map.remove(e);
n--;
if(!swim(j))
sink(j);
}
void decreasePriority(Key e){
if(map.containsKey(e)){
int j = map.get(e);
swim(j);
}
else insert(e);
}
private void swap(int i, int j) {
Key t = heap[i];
heap[i] = heap[j];
heap[j] = t;
map.replace(heap[i], i);
map.replace(heap[j], j);
}
private boolean swim(int j){
boolean change = false;
int parent;
while( (parent = (j-1)/2 ) >= 0){
if(heap[j].compareTo(heap[parent]) < 0){
swap(j,parent);
j = parent;
change = true;
}
else break;
}
return change;
}
private void sink(int j){
while(j <= n/2 - 1){
int leftChild = j*2 + 1, rightChild = leftChild + 1, s;
if(rightChild >= n)
s = leftChild;
else
s = heap[leftChild].compareTo(heap[rightChild]) < 0 ? leftChild : rightChild;
if(heap[j].compareTo(heap[s]) > 0){
swap(j,s);
j = s;
}
else break;
}
}
#Override
public String toString() {
String res = "[";
int i;
for (i = 0; i < n-1; i++){
res += heap[i] + ", ";
}
res += heap[i]+"]";
return res;
}
}
Edit: Be careful with your class comparator.
I am trying to implement min-heap which includes methods like insert,delete and heap sort.I am using implementation of max-heap and trying to convert it to min-heap.But,i am having some minor issues.It's a very straight-forward method ,but i am missing something,which i am not able to get.
This is the Helper Max-heap implementation i am using:
public void trickleDown(int index)
{
int largerChild;
Node top = heapArray[index]; // save root
while(index < currentSize/2) // while node has at
{ // least one child,
int leftChild = 2*index+1;
int rightChild = leftChild+1;
// find larger child
if( rightChild < currentSize && // (rightChild exists?)
heapArray[leftChild].getKey() <
heapArray[rightChild].getKey() )
largerChild = rightChild;
else
largerChild = leftChild;
// top >= largerChild?
if(top.getKey() >= heapArray[largerChild].getKey())
break;
// shift child up
heapArray[index] = heapArray[largerChild];
index = largerChild; // go down
} // end while
heapArray[index] = top; // index <- root
} // end trickleDown()
/////// My Implementation
/** Removes the top element of the heap and returns it.
*
* Complexity: O(log n)
* #return Top (min/max) element of the heap.
* #throws IllegalStateException if the heap is empty.
*/
T remove() {
if (size == 0) {
throw new IllegalStateException();
}
Comparable root = data[0];
data[0] = data[size-1];
size--;
trickleDown(0);
return (T) root;
}
private void trickleDown(int i) {
int largerChild;
Comparable top = data[i]; // save root
while(i > size/2 ) // not on bottom row{
int leftChild = left(i);
int rightChild = right(i);
if(rightChild > size && data[left(i)].compareTo(data[right(i)]) < 0 )
largerChild = leftChild;
else
largerChild = rightChild;
if(data[i].compareTo(data[right(i)]) <= 0 )
break;
data[i] = data[largerChild];
i = largerChild;
}
data[i] = top;
}
///// Test File
void checkHeapOrder(MinHeap h) {
assertTrue(h != null);
for(int i = 1; i < h.size() / 2; ++i)
assertTrue("Heap order property is broken at element at position "
+ i,
h.data[i].compareTo(h.data[i*2]) < 0 &&
h.data[i].compareTo(h.data[i*2 + 1]) < 0);
}
#Test
public void testRemove() {
System.out.println("remove");
MinHeap h = new MinHeap(10);
boolean throws_exception = false;
try {
h.remove();
} catch (IllegalStateException e) {
throws_exception = true;
} catch (Throwable e) {
}
assertTrue("remove throws an exception when empty", throws_exception);
// Permutation of 0...9
int[] input = { 0, 5, 9, 2, 3, 1, 6, 8, 7, 4 };
for(int i : input)
h.insert(i);
assertTrue(h.isFull());
for(int i = 10; i > 0; --i) {
assertEquals(h.size(), i);
Integer x = (Integer)h.remove();
assertEquals(x, new Integer(10-i)); // Items are removed in correct order
checkHeapOrder(h);
}
testRemove Failed: expected<0> but was <1>
I am pretty sure that the code is simple and i have tried to change everything from max to min,but just missing on with something,which i am having a hard time figuring out.
I want to remove the rightmost half of the list but this code sometimes is okay other time is not .
If l contains A → B → C → D → E, then after calling
l.removeRightmostHalf(), l becomes A → B → C.
public void removeRightmostHalf() {
if (size % 2 != 0)
{
current = (size / 2) + 1;
while(current <= size)
{
for (int i = current + 1; i < size; i++)
nodes[i-1] = nodes[i];
size--;
if (size == 0)
current = -1;
else if (current == size)
current = 0;
}
}
else
{
current = (size / 2);
while(current <= size)
{
for (int i = current + 1; i < size; i++)
nodes[i-1] = nodes[i];
size--;
if (size == 0)
current = -1;
else if (current == size)
current = 0;
}
}
}
public void removeRightmostHalf()
{
if (size % 2 != 0)
current = (size / 2) + 1;
else
current=size/2;
nodes.subList(current,size).clear()
}
This code will do the work try it and tell me .
if my answer is right to you please don't forget to select it as correct answer.
public void removeRightmostHalf() {
if (size % 2 != 0)
size=(size / 2)+1;
else size=(size / 2);
}
how is this do the work ?
because the question is to delete the right half so decreasing the size to the half , that will make the right part of the array unreachable , just like what Arraylist.Remove() does .
I implemented the iterative deepening a-star search(for the 8-Puzzle problem, but can accept other problems) and ran it on an input. It ran unsuccessfully for 2 hrs. For simpler inputs that are close to goal node it works fine. Others have got it to work for this input. I am not sure whether my implementation is just inefficient or goes into an infinite loop
PuzzleSolver.java$ida
/** Accepts start node root and string identifying whihc heuristic to use
* h1 is number of misplaced tiles and h2 is Manhattan distance
*/
private Node ida(Node root, final String h) {
PriorityQueue<DNode> frontier = new PriorityQueue<DNode>(10, new Comparator<DNode>(){
#Override
public int compare(DNode n1, DNode n2) {
if(h == "h1") {
if(n1.depth + h1(n1.node) > n2.depth + h1(n2.node)) return 1;
if(n1.depth + h1(n1.node) < n2.depth + h1(n2.node)) return -1;
return 0;
}
if(h == "h2") {
if(n1.depth + h2(n1.node) > n2.depth + h2(n2.node)) return 1;
if(n1.depth + h2(n1.node) < n2.depth + h2(n2.node)) return -1;
return 0;
}
return 0;
}});
ArrayList<Node> explored = new ArrayList<Node>();
Node soln = null;
DNode start = new DNode(root, 1);
frontier.add(start);
int d = 0;
int flimit = (h == "h1" ? h1(start.node) : h2(start.node));
int min = flimit;
while(true) {
DNode dn = frontier.poll();
if(dn == null) {
frontier.add(start);
d = 0;
flimit = min;
continue;
}
d = dn.depth;
Node n = dn.node;
//n.print();
if(goalCheck(n)){
return n;
}
for(int i = 0;i < ops.length;i++) {
String op = ops[i];
if(n.applicable(op)) {
soln = n.applyOp(op);
int h_cost;
if(h == "h1") h_cost = h1(soln);
else h_cost = h2(soln);
if(!checkDup(explored,soln) && d + 1 + h_cost < flimit) {
frontier.add(new DNode(soln, d + 1));
DNode least = frontier.peek();
min = least.depth + (h == "h1" ? h1(least.node) : h2(least.node));
}
}
}
explored.add(n);
max_list_size = Math.max(max_list_size, frontier.size() + explored.size());
}
}
PuzzleSolver.java$CheckDup
private boolean checkDup(ArrayList<Node> explored, Node soln) {
boolean isDuplicate = false;
for(Node n:explored) {
boolean equal = true;
for(int i = 0;i < soln.size; i++) {
for(int j =0 ;j<soln.size;j++) {
if(soln.state.get(i).get(j) != n.state.get(i).get(j)) {
equal = false;
}
}
}
isDuplicate |= equal;
}
return isDuplicate;
}
Start state(failed):
1 2 3
8 - 4
7 6 5
Goal state:
1 3 4
8 6 2
7 - 5
(worked for 1 3 4 8 6 0 7 5 2)
I have not included Node.java because I am pretty sure it works after running other search algorithms like best-first, dfs. It is difficult to provide an SCCE, so I am just asking for help spotting any obvious bugs in the ida implementation.
EDIT: Solved issue, but still trying to figure out a termination condition when the goal is not reachable. IDA* does not keep a list of explored nodes, so how can I know if I have covered the whole solution space?
Your checkDup function is very inefficient. I recommend using a HashSet:
http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
Your function has a cost linear in the size of the set, while the contains method of HashSet has a constant cost.
Strings in java are compared with equals:
Java String.equals versus ==
There may be other problems, but these are the two most obvious ones I spotted after a quick check of your code.
There was a mistake in the way I calculated the new flimit. It did not cause a problem in the other cases because the flimit of the successor was such that it did not cause it to loop infinitely. Also the condition should f(current node) <= cutoff. and not '<' as I took.
Updated version:
private Node ida(Node root, final String h) {
PriorityQueue<DNode> frontier = new PriorityQueue<DNode>(10, new Comparator<DNode>(){
#Override
public int compare(DNode n1, DNode n2) {
if(h == "h1") {
if(n1.depth + h1(n1.node) > n2.depth + h1(n2.node)) return 1;
if(n1.depth + h1(n1.node) < n2.depth + h1(n2.node)) return -1;
return 0;
}
if(h == "h2") {
if(n1.depth + h2(n1.node) > n2.depth + h2(n2.node)) return 1;
if(n1.depth + h2(n1.node) < n2.depth + h2(n2.node)) return -1;
return 0;
}
return 0;
}});
ArrayList<Node> explored = new ArrayList<Node>();
Node soln = null;
DNode start = new DNode(root, 1);
frontier.add(start);
int d = 0;
int flimit = (h == "h1" ? h1(start.node) : h2(start.node));
int min = flimit;
while(true) {
DNode dn = frontier.poll();
if(dn == null) {
explored.clear();
frontier.add(start);
d = 0;
flimit = min;
continue;
}
d = dn.depth;
Node n = dn.node;
//n.print();
if(goalCheck(n)){
return n;
}
min = Integer.MAX_VALUE;
for(int i = 0;i < ops.length;i++) {
String op = ops[i];
if(n.applicable(op)) {
soln = n.applyOp(op);
int h_cost;
if(h == "h1") h_cost = h1(soln);
else h_cost = h2(soln);
if(!checkDup(explored,soln)) {
if(d + 1 + h_cost <= flimit) {
frontier.add(new DNode(soln, d + 1));
}
else {
if(d + 1 + h_cost < min)min = d + 1 + h_cost;
}
}
}
}
explored.add(n);
max_list_size = Math.max(max_list_size, frontier.size() + explored.size());
}
}