I am learning to use heaps and as an exercise I am trying to write a program using a heap class I have created to sort words. I have read in words from a file and added them to the heap successfully. I am having some trouble figuring out how I can print out a sorted list of the words. From my understanding of how a min-heap works, if I remove from the min/root node they will always be removed in sorted order. So far I have tried out to do a simple for loop but, only half of the heap is being removed.
My Main Attempt
public static void main(String[] args) {
Heap heap = new Heap();
heap = read( heap );
for( int i = 0; i < heap.getSize(); i++){
heap.removeMin();
}
heap.printHeap();
}
This is the remove function in my Heap Class
public Node removeMin(){
Node min = heap.get(0);
int index = heap.size() - 1;
Node last = heap.remove(index);
if( index > 0 ){
heap.set( 0, last );
Node root = heap.get(0);
int end = heap.size() - 1;
index = 0;
boolean done = false;
while(!done){
if(getLCLoc(index) <= end ){
//left exists
Node child = getNodeAt( getLCLoc(index) );
int childLoc = getLCLoc(index);
if( getRCLoc(index) <= end ){
//right exists
if( getNodeAt( getRCLoc(index) ).getData().compareToIgnoreCase( child.getData() ) < 0 ){
child = getNodeAt( getRCLoc(index) );
childLoc = getRCLoc(index);
}
}
if(child.getData().compareToIgnoreCase( root.getData() ) < 0 ){
heap.set( index, child );
index = childLoc;
}else{
done = true;
}
}else{
//no children
done = true;
}
}
heap.set( index, root );
}
return min;
}
I would guess that remove() decreases heap size by 1. So, for each iteration of your loop, you are incrementing i by 1 and decrementing heap size by 1. I would change to a while loop that runs while heapsize >0.
Related
I've been grinding leetcode recently and am perplexed on why my solution is timing out when I submit it to Leetcode.
Here is the question:
https://leetcode.com/explore/learn/card/data-structure-tree/133/conclusion/942/
Given inorder and postorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
For example, given
inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
Here is my solution that times out in one of the test cases:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder == null || inorder.length == 0) {
return null; // input error
}
if (postorder == null || postorder.length == 0) {
return null; // input error
}
if (postorder.length != inorder.length) {
return null; // input error
}
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
return buildBinaryTree(inOrder, postOrder);
}
public TreeNode buildBinaryTree(List<Integer> inOrder, List<Integer> postOrder) {
boolean found = false;
int root = 0;
int rootIndex = 0;
// for given in-order scan the post-order right to left to find the root
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
root = inOrder.get(rootIndex);
found = true;
break;
}
}
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
if (rootIndex > 0) {
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
}
if ((rootIndex + 1) < inOrder.size()) {
rightOfRoot.addAll(inOrder.subList(rootIndex + 1, inOrder.size()));
}
TreeNode node = new TreeNode(root);
node.left = buildBinaryTree(leftOfRoot, postOrder);
node.right = buildBinaryTree(rightOfRoot, postOrder);
return node;
}
return null;
}
}
Can anyone help determine why this is happening? I'm thinking it is the Leetcode judge at fault here and my code is fine.
Leetcode's judge is probably OK. This code is too casual about nested linear array operations and heap allocations. Creating ArrayLists and calling contains, addAll, subList and indexOf may appear innocuous, but they should all be thought of as extremely expensive operations when inside a recursive function that spawns two child calls in every frame.
Let's unpack the code a bit:
List<Integer> inOrder = new ArrayList<Integer>();
List<Integer> postOrder = new ArrayList<Integer>();
for (int i = 0; i < inorder.length; i++) {
inOrder.add(inorder[i]);
postOrder.add(postorder[i]);
}
This is a minor up-front cost but it's an omen of things to come. We've done 2 heap allocations that weren't necessary and walked n. I'd stick to primitive arrays here--no need to allocate objects other than the result nodes. A lookup map for inOrder with value -> index pairs might be useful to allocate if you feel compelled to create a supporting data structure here.
Next, we step into buildBinaryTree. Its structure is basically:
function buildBinaryTree(root) {
// do some stuff
if (not base case reached) {
buildBinaryTree(root.left)
buildBinaryTree(root.right)
}
}
This is linear on the number of nodes in the tree, so it's important that // do some stuff is efficient, hopefully constant time. Walking n in this function would give us quadratic complexity.
Next there's
for (int j = postOrder.size() - 1; j >= 0 && !found; j--) {
root = postOrder.get(j);
if (inOrder.contains(root)) {
rootIndex = inOrder.indexOf(root);
This looks bad, but by definition the root is always the last element in a postorder traversal array, so if we keep a pointer to it, we can remove this outer loop. You can use indexOf directly and avoid the contains call since indexOf returns -1 to indicate a failed search.
The code:
if (found) {
List<Integer> leftOfRoot = new ArrayList<Integer>();
List<Integer> rightOfRoot = new ArrayList<Integer>();
does more unnecessary heap allocations for every call frame.
Here,
leftOfRoot.addAll(inOrder.subList(0, rootIndex));
Walks the list twice, once to create the sublist and again to add the entire sublist to the ArrayList. Repeat for the right subtree for two full walks on n per frame. Using start and end indices per call frame means you never need to allocate heap memory or copy anything to prepare the next call. Adjust the indices and pass a reference to the same two arrays along the entire time.
I recommend running your code with a profiler to see exactly how much time is spent copying and scanning your ArrayLists. The correct implementation should do at most one walk through one of the lists per call frame to locate root in inOrder. No array copying should be done at all.
With these modifications, you should be able to pass, although wrangling the pointers for this problem is not obvious. A hint that may help is this: recursively process the right subtree before the left.
Yes, it would be much faster with arrays. Try this:
public static TreeNode buildTree(int[] inorder, int[] postorder, int start,
int end) {
for (int i = postorder.length-1; i >= 0; --i) {
int root = postorder[i];
int index = indexOf(inorder, start, end, root);
if (index >= 0) {
TreeNode left = index == start
? null
: buildTree(inorder, postorder, start, index);
TreeNode right = index+1 == end
? null
: buildTree(inorder, postorder, index+1, end);
return new TreeNode(root, left, right);
}
}
return null;
}
private static int indexOf(int[] array, int start, int end, int value) {
for (int i = start; i < end; ++i) {
if (array[i] == value) {
return i;
}
}
return -1;
}
I've made a simple 15puzzle game using A-star algorithm with Manhattan Distance.
For easy problems it works, but the solution isn't the optimal one.
For example, if a movement is:
Right->Up
my solution would be:
Right->Up->Left->Down->Right->Up
If i have a hard game to solve, it takes infinite time and get no solution to problem, I think because of this problem.
To implement my game I have followed wikipedia pseudocode of A* algorithm.
Here is my AStar function:
public ArrayList<String> solution(Vector<Integer> start){
ArrayList<String> movePath = new ArrayList<String>(); //Path to solution
PriorityQueue<Node> closedQueue = new PriorityQueue<Node>(500,new Comparator<Node>() {
#Override public int compare(Node a,Node b) {
return a.get_fScore() - b.get_fScore();
}
});
Node node = new Node(start,movePath,heuristic);
int cnt =0;
openQueue.add(node);
while(!openQueue.isEmpty() ) {
//Alt if it takes too much time (ToRemove)
if(cnt == (150)*1000) {
ArrayList<String> noResult = new ArrayList<String>();
noResult.add("Timeout");
return noResult;
}
Node bestNode = openQueue.remove(); //Remove best node from openQueue
closedQueue.add(bestNode); //Insert its to closedQueue
cnt++;
if( cnt % 10000 == 0) {
System.out.printf("Analizzo %,d posizioni. Queue Size = %,d\n", cnt, openQueue.size());
}
//Get first step from bestNode and add to movePath
if(!bestNode.isEmptyMoves()) {
String step = bestNode.get_moves().get(0);
movePath.add(step);
}
//Exit Condition
if(bestNode.get_hScore() == 0) {
return bestNode.get_moves();
}
//Looking for childs
Vector<Node> childs = get_nextMoves(bestNode);
for(int i=0; i<childs.size(); i++) {
if(closedQueue.contains(childs.elementAt(i)))
continue;
childs.elementAt(i).set_gScore(bestNode.get_gScore()+1); //Increment level in tree
if(!openQueue.contains(childs.elementAt(i)))
openQueue.add(childs.elementAt(i));
else {
//!Never reached this level!
System.out.println("Here!");
//TODO Copy child from openQueue to closedQueue
}
}
}
return null;
That is my function to find neighbours:
public Vector<Node> get_nextMoves(Node act){
Vector<Node> steps = new Vector<Node>();
int position = act.get_valuePos(0);
String lastMove = act.get_lastMove();
//System.out.println(lastMove);
//Right Child
if(position + 1 < 16 && position + 1!=3 && position + 1!=7 && position+1 !=11 && lastMove !="Left") {
int temp_pos[] = copyToArray(act.get_posVect());//Copy array of positions of ACT to a temp_pos array
temp_pos[position] = temp_pos[position+1]; //Switch 0 position with Right position
temp_pos[position+1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i)); //Save old steps
}
temp_moves.add("Right");//And add new one
Node child = new Node(temp_pos,temp_moves,act.get_heuristic()); //New Node
steps.addElement(child);//Added to vector
}
//Left Child
if(position - 1 >= 0 && position - 1 != 4 && position - 1 != 8 && position - 1 != 12 && lastMove !="Right") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-1];
temp_pos[position-1] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Left");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Up Child
if(position - 4 >= 0 && lastMove !="Down") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position-4];
temp_pos[position-4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Up");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
//Down Child
if(position + 4 < 16 && lastMove !="Up") {
int temp_pos[] = copyToArray(act.get_posVect());
temp_pos[position] = temp_pos[position+4];
temp_pos[position+4] = 0;
ArrayList<String> temp_moves = new ArrayList<String>();
for(int i=0; i<act.get_moves().size(); i++) {
temp_moves.add(act.get_moves().get(i));
}
temp_moves.add("Down");
Node child = new Node(temp_pos,temp_moves,act.get_heuristic());
steps.addElement(child);
}
return steps;
And that is my ManhattanDistance function:
public int calcolaDist(Vector<Integer> A) {
int result = 0;
Vector<Integer> goal_Mat = initialize_Mat();
for(int i=0; i<16; i++) {
int x_goal = (goal_Mat.indexOf(i))/4;
int y_goal = (goal_Mat.indexOf(i))%4;
int x_def = (A.indexOf(i))/4;
int y_def = (A.indexOf(i))%4;
if(A.elementAt(i) > 0) {
result += Math.abs(x_def - x_goal);
result += Math.abs(y_def - y_goal);
}
}
return result;
If my puzzle is:
start = {1,3,0,4,5,2,7,8,9,6,10,11,13,14,15,12}
My solution will be:
[Left, Down, Down, Right, Down, Right, Up, Left, Down, Right, Up, Left, Down, Right]
I know that using Vectors isn't a good choice and my code is "a little" dirty, but I'm going to clean its as soon as I get out of that problem!
Thank you all!
First, I see a bit of confusion in your code with the OPEN and CLOSED queues. The OPEN queue should be the one that manages the priority of the nodes (PriorityQueue). This is not needed for CLOSED, which only stores the visited nodes and their cost (maybe your algorithm will be more efficient changing CLOSED by a HashSet or HashMap to avoid ordering the nodes in CLOSED as well). I can't see in your code how you initialized the OPEN queue, but maybe that is one issue with your implementation of A*.
The other issue I see with your code is that with A*-based algorithms, you need to manage the situation in which you reach a node that is already in OPEN/CLOSED, but with a different cost. This can happen if you visit a node from different parents, or you enter in a loop. The algorithm will not work properly if you are not taking that into account.
If you visit a node that is already in the OPEN queue, and the new node has a lower f-score, you should remove the old node from OPEN and insert the one with the lower cost.
If the node has a higher cost (in OPEN or CLOSED) then you should simply discard that node to avoid loops.
The problem is though, but the state space is finite and the algorithm should finish at some point. I see that your implementation is in Java. Maybe it would be helpful for you if you take a look to the library Hipster4j, which has an implementation of A*, and an example solving the 8-puzzle.
I hope my answer helps. Good luck!
i'm tasked with creating a method which has the same functionality as splice however I cannot get the appropriate value into the appropriate index. My code works as follows,
public void PlaceElementAt(int newValue, int index) throws ArrayIndexOutOfBoundsException {
//check that index is valid
if (index >= 0 && index <= data.length) { //Checks that the index is within position 0 and 7 by default.
System.out.println ("Index is valid"); //returns index is valid if so
}
//increase size if necessary
if (data.length == numElements) { //checking if the number of elements is filling the spaces
doubleCapacity(); // calls upon the double capacity method if it is
}
if (numElements==0) {
data[numElements] = newValue;
System.out.println ("Element: " + data[numElements] + " at index: " + index);
numElements++;
}
//shuffle values down from index
else {
int bottompos = numElements-1;
int loopcount = numElements-index;
int NewBottom = numElements+1;
for (int i=0; i<loopcount; i++){
data[bottompos]=data[NewBottom];
bottompos--;
NewBottom--;
}
//insert newValue at index
data[numElements] = newValue;
System.out.println ("Element: " + data[numElements] +" at index: " + index);
numElements++;
}
}
My issue is apparent when I later give the commands in my main method.
myData.PlaceElementAt(3,0)
myData.PlaceElementAt(2,5)
myData.PlaceElementAt(7,3)
Once I check my breakpoints i see the values are being added to the array however they are being added on a 1 by 1 basis starting from index 0. Any suggestions greatly helps.
I'm making some assumptions about how your class is structured (adjust as needed), but generally I would recommend shifting right as it will simplify the overall process. Essentially we have an array with maximum allowed size given by MAX and current size given by size. Any time we add to the array, we increment the value of size by 1 (such as insertions or adding to the back of our list). Now, let's say we want to insert a value at index. This will entail shifting all elements at and right of this index by 1 to the right and then inserting our value in the space we have made. Before doing any inserting we first need to check that we have enough space to insert the item. If there is not enough space, we will need to allocate additional space, prohibit the insertion, or some other alternative. In your case, it looks like you want to allocate more space.
class MyList
{
private int MAX = 6;
private int size = 0;
private int[] array;
public MyList()
{
array = new int[MAX];
}
public void placeElementAt(int value, int index)
{
if (size == 0)
{
// If size is 0, just insert the value at index 0.
array[size++] = value;
return;
}
if (index < 0 || index >= size)
{
// Index is out of bounds.
System.out.println("Invalid index.");
return;
}
if (size >= MAX)
{
// Max capacity reached -> allocate more space.
doubleCapacity();
}
// Shift all elements at and above index right by 1.
for (int i = size - 1; i >= index; i--)
{
array[i + 1] = array[i];
}
// Insert element.
array[index] = value;
size++;
}
public void doubleCapacity()
{
int[] newArray = new int[MAX * 2];
// Copy old elements to new array.
for (int i = 0; i < size; i++)
{
newArray[i] = array[i];
}
// Double MAX to reflect new array.
MAX *= 2;
array = newArray;
System.out.println("Doubled");
}
public void add(int value)
{
if (size >= MAX)
{
// Max capacity reached -> allocate more space.
doubleCapacity();
}
// Add the element to the back of the list.
array[size++] = value;
}
public void print()
{
for (int i = 0; i < size; i++)
{
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args)
{
MyList data = new MyList();
data.placeElementAt(1, 0);
data.print();
data.placeElementAt(2, 0);
data.print();
data.placeElementAt(3, 0);
data.print();
data.placeElementAt(5, 0);
data.print();
data.placeElementAt(3, 0);
data.print();
data.placeElementAt(9, 0);
data.print();
data.placeElementAt(4, 0);
data.print();
data.placeElementAt(6, 0);
data.print();
}
}
The output of this program (with initial MAX = 6) would be...
1
2 1
3 2 1
5 3 2 1
3 5 3 2 1
9 3 5 3 2 1
Doubled
4 9 3 5 3 2 1
6 4 9 3 5 3 2 1
Well, seeing your code, you're receiving a "index" parameter. But you're not using the index to insert on your array.
Your code:
data[numElements] = newValue;
numElements++;
Try this:
data[index] = newValue;
numElements++;
I think this will solve it, but later you'll have to handle the cases where the specified index already have an element.
Code from PriorityQueue:
private E removeAt(int i) {
assert i >= 0 && i < size;
modCount++;
int s = --size; // <- Why???
if (s == i) // removed last element
queue[i] = null;
else {
E moved = (E) queue[s];
queue[s] = null;
siftDown(i, moved);
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
What's differences between s = --size and s = size? Anybody could help? Thanks in advance.
int s = --size; is a pre-decrement operator, and that is not equivalent to int s = size;. It is equivalent to
int s = (size = (size - 1));
or
size = size - 1;
int s = size;
But it is shorter than both of those.
If you use s = size, then you need to add line size = size - 1. As you have to decrease the queue size after removal of an element.
a = i++ means a = i ; i = i + 1
a = ++i means i = i + 1 ; a = i ;
the same to minus
PriorityQueue is based on array private transient Object[] queue;. In PriorityQueue this array stores data of binary heap. removeAt(int) is an operation on removing an element from heap. You remove element from heap by taking the last element of the heap (here you use int s = --size to assign to s the index of last element; alternatively you can do int s = heap.length - 1).
Then delete the element you want queue[s] = null; and do work to fill the gap in array with sifting operations siftDown, siftUp.
im trying to implement a basic form of binary search. i created an array and filled out with linear values. Now just trying to sort through it to find a number and its index.. The problem is that it is getting stuck in a constant loop and returning zero. it goes through the nested loop because it prints but is unable to find the target value. Below is the code
for (int i= 1; i < 10000 ; i++){
studentID[i] = i;
}
Students studentIDNumber = new Students();
studentIDNumber.binarySearch(studentID, 400);
public void binarySearch(int[] studentID, int targetID){
System.out.println("helloworld");
int position = -1;
int suspect;
int suspectIndex = 0;
int lastSuspectIndex = studentID.length-1;
while(position == -1)
{
assert(suspectIndex<lastSuspectIndex);
suspectIndex = ((studentID.length-1)/2);
lastSuspectIndex =suspectIndex;
suspect=studentID[suspectIndex];
System.out.println(suspect);
if(suspect == targetID){
position = suspectIndex;
System.out.println(suspectIndex +" is where the ID #"+targetID+" is sotred");
break;
}
if(suspect < targetID){
suspectIndex= suspectIndex+(suspectIndex/2);
position = -1;
}
if(suspect > targetID){
suspectIndex= suspectIndex-(suspectIndex/2);
position = -1;}
else {
System.out.println("ID not found " );
}
}
}
On this line:
suspectIndex = ((studentID.length-1)/2);
suspectIndex will be the same for every loop iteration. Initialize the variable once before the loop but not at the start of the loop itself.