Weighted Quick-Union with Path Compression algorithm - java

There is a "Weighted Quick-Union with Path Compression" algorithm.
The code:
public class WeightedQU
{
private int[] id;
private int[] iz;
public WeightedQU(int N)
{
id = new int[N];
iz = new int[N];
for(int i = 0; i < id.length; i++)
{
iz[i] = i;
id[i] = i;
}
}
public int root(int i)
{
while(i != id[i])
{
id[i] = id[id[i]]; // this line represents "path compression"
i = id[i];
}
return i;
}
public boolean connected(int p, int q)
{
return root(p) == root(q);
}
public void union(int p, int q) // here iz[] is used to "weighting"
{
int i = root(p);
int j = root(q);
if(iz[i] < iz[j])
{
id[i] = j;
iz[j] += iz[i];
}
else
{
id[j] = i;
iz[i] += iz[j];
}
}
}
Questions:
How does the path compression work? id[i] = id[id[i]] means that we reach only the second ancester of our node, not the root.
iz[] contains integers from 0 to N-1. How does iz[] help us know the number of elements in the set?
Can someone clarify this for me?

First understand that id is a forest. id[i] is the parent of i. If id[i] == i it means that i is a root.
For some root i (where id[i] == i) then iz[i] is the number of elements in the tree rooted at i.
public int root(int i)
{
while(i != id[i])
{
id[i] = id[id[i]]; // this line represents "path compression"
i = id[i];
}
return i;
}
How does the path compression work? id[i] = id[id[i]] means that we reach only the second ancester of our node, not the root.
As we are ascending the tree to find the root we move nodes from their parents to their grandparents. This partially flattens the tree. Notice that this operation doesn't change which tree the node is a member of, this is all we are interested in. This is the path compression technique.
(You did notice the loop right? while(i == id[i]) terminates once i is a root node)
iz[] contains integers from 0 to N-1. How does iz[] help us know the number of elements in the set?
There is a transcription error in the code:
for(int i = 0; i < id.length; i++)
{
iz[i] = i; // WRONG
id[i] = i;
}
This is the correct version:
for(int i = 0; i < id.length; i++)
{
iz[i] = 1; // RIGHT
id[i] = i;
}
iz[i] is the number of elements for a tree rooted at i (or if i is not a root then iz[i] is undefined). So it should be initialized to 1, not i. Initially each element is a seperate "singleton" tree of size 1.

id[i] = id[id[i]]; // this line represents "path compression"
The above code is "Simpler one-pass variant" as mentioned in the slide of Union Find (Algorithms, Part I by Kevin Wayne and Robert Sedgewick). Therefore your guess for question 1 is correct. Each examined node points to its grandparent.
To make each examined node points to the root we will need two-pass implementation:
/**
* Returns the component identifier for the component containing site <tt>p</tt>.
* #param p the integer representing one site
* #return the component identifier for the component containing site <tt>p</tt>
* #throws java.lang.IndexOutOfBoundsException unless 0 <= p < N
*/
public int find(int p) {
int root = p;
while (root != id[root])
root = id[root];
while (p != root) {
int newp = id[p];
id[p] = root;
p = newp;
}
return root;
}
Reference:
http://algs4.cs.princeton.edu/15uf/WeightedQuickUnionPathCompressionUF.java.html

One more thing to be noted here:
While finding the root when we are making id[i]=id[id[i]] i.e; making i under its grand parent
-then size of id[i] will decrease by size of i i,e; iz[id[i]]-=iz[i]
Now this makes code perfectly correct.
I am not sure about this but intuitively i feel,
Its absence does not cause problems because we are always comparing size of the roots.

Question 1.
It is not right to say that the line id[i] = id[id[i]]; only reaches the second ancestor of the root.You will realize that while loop while(i != id[i]) stops only when the node i is pointing at the root i.e when i == id[i].By this time we shall have pointed the node to the root using the line id[i] = id[id[i]]; where the inner id[i] is the root.
Question 2.
You are wrong to initialize iz[i] = i; actually it should be iz[i] = 1; meaning, each and every node size is initialized by 1 at the beginning since they are of size 1.
In the union function you realize that we have the lines iz[j] += iz[i]; and iz[i] += iz[j]; which updates the size of the root node to be the sum of the sizes of the two components joined together. This efficiently updates the nodes sizes.

Related

Solution timing out for question: build binary tree from inorder and postorder

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;
}

15 puzzle with AStar Algorithm

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!

Find the max path from root to leaf of a n-ary tree without including values of two adjacent nodes in the sum

I recently got interviewed and was asked the following question.
Given an n-ary tree, find the maximum path from root to leaf such that maximum path does not contain values from any two adjacent nodes.
(Another edit: The nodes would only have positive values.)
(Edit from comments: An adjacent node means node that share a direct edge. Because its a tree, it means parent-child. So if I include parent, I can not include child and vice versa.)
For example:
5
/ \
8 10
/ \ / \
1 3 7 9
In the above example, the maximum path without two adjacent would be 14 along the path 5->10->9. I include 5 and 9 in the final sum but not 10 because it would violate the no two adjacent nodes condition.
I suggested the following algorithm. While I was fairly sure about it, my interviewer did not seem confident about it. Hence, I wanted to double check if my algorithm was correct or not. It seemed to work on various test cases I could think of:
For each node X, let F(X) be the maximum sum from root to X without two adjacent values in the maximum sum.
The formula for calculating F(X) = Max(F(parent(X)), val(X) + F(grandParent(X)));
Solution would have been
Solution = Max(F(Leaf Nodes))
This was roughly the code I came up with:
class Node
{
int coins;
List<Node> edges;
public Node(int coins, List<Node> edges)
{
this.coins = coins;
this.edges = edges;
}
}
class Tree
{
int maxPath = Integer.MIN_VALUE;
private boolean isLeafNode(Node node)
{
int size = node.edges.size();
for(int i = 0; i < size; i++)
{
if(node.edges.get(i) != null)
return false;
}
return true;
}
// previous[0] = max value obtained from parent
// previous[1] = max value obtained from grandparent
private void helper(Node node, int[] previous)
{
int max = Math.max(previous[0], max.val + previous[1]);
//leaf node
if(isLeafNode(node))
{
maxPath = Math.max(maxPath, max);
return;
}
int[] temp= new int[2];
temp[0] = max;
temp[1] = prev[0];
for(int i = 0; i < node.edges.size(); i++)
{
if(node.edges.get(i) != null)
{
helper(node.edges.get(i), temp);
}
}
}
public int findMax(Node node)
{
int[] prev = new int[2];
prev[0] = 0;
prev[1] = 0;
if(node == null) return 0;
helper(node, prev);
return maxPath;
}
}
Edit: Forgot to mention that my primary purpose in asking this question is to know if my algorithm was correct rather than ask for a new algorithm.
Edit: I have a reason to believe that my algorithm should also have worked.
I was scouring the internet for similar questions and came across this question:
https://leetcode.com/problems/house-robber/?tab=Description
It is pretty similar to the problem above except that it is now an array instead of the tree.
The formal F(X) = Max(F(X-1), a[x] + F(X-2)) works in this case.
Here is my accepted code:
public class Solution {
public int rob(int[] nums) {
int[] dp = new int[nums.length];
if(nums.length < 1) return 0;
dp[0] = nums[0];
if(nums.length < 2) return nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < nums.length; i++)
{
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
}
return dp[nums.length-1];
}
}
The natural solution would be to compute for each node X two values: max path from X to leaf including X and max path from X to leaf, excluding X, let's call them MaxPath(X) and MaxExcluded(X).
For leaf L MaxPath(L) is Value(L) and MaxExcluded(L) is 0.
For internal node X:
MaxPath(X) = Value(X) + Max over child Y of: MaxExcluded(Y)
MaxExcluded(X) = Max over child Y of : Max(MaxExcluded(Y), MaxPath(Y))
The first line means that if you include X, you have to exclude its children. The second means that if you exclude X, you are free to either include or exclude its children.
It's a simple recursive function on nodes which can be computed going leaves-to-parents in O(size of the tree).
Edit: The recursive relation does also work top-down, and in this case you can indeed eliminate storing two values by the observation that MaxExcluded(Y) is actually MaxPath(Parent(Y)), which gives the solution given in the question.
Implementation of what #RafałDowgird explained.
/* 5
* 8 10
* 1 3 7 9
* 4 5 6 11 13 14 3 4
*
*
*/
public class app1 {
public static void main(String[] args) {
Node root = new Node(5);
root.left = new Node(8);root.right = new Node(10);
root.left.left = new Node(1);root.left.right = new Node(3);
root.right.left = new Node(7);root.right.right = new Node(9);
root.left.left.left = new Node(4);root.left.left.right = new Node(5);
root.left.right.left = new Node(6);root.left.right.right = new Node(11);
root.right.left.left = new Node(13);root.right.left.right = new Node(14);
root.right.right.right = new Node(4);
System.out.println(findMaxPath(root));
}
private static int findMaxPath(Node root) {
if (root == null) return 0;
int maxInclude = root.data + findMaxPathExcluded(root);
int maxExcludeLeft = Math.max(findMaxPath(root.left), findMaxPathExcluded(root.left));
int maxExcludeRight = Math.max(findMaxPath(root.right), findMaxPathExcluded(root.right));
return Math.max(maxInclude, Math.max(maxExcludeLeft, maxExcludeRight));
}
private static int findMaxPathExcluded(Node root) {
if(root == null) return 0;
int left1 = root.left!=null ? findMaxPath(root.left.left) : 0;
int right1 = root.left!=null ? findMaxPath(root.left.right) : 0;
int left2 = root.right!=null ? findMaxPath(root.right.left) : 0;
int right2 = root.right!=null ? findMaxPath(root.right.right) : 0;
return Math.max(left1, Math.max(right1, Math.max(left2, right2)));
}
}
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data=data;
}
}

Dijkstra's Algorithm Java-- Distance not right

I am trying to code dijkstra's algorithm, starting at any vertex I need to show the distance and print the path of nodes. It works for vertex 2,4, and 5, but for 1 and 3 it gets messed up. It's probably something stupidly small, but I can't see it.
public static void main(String[] args)
{
int INF = Integer.MAX_VALUE;
int verticies = 5;
int W[][] = {{INF,7,4,6,1},
{0,INF,0,0,0},
{0,2,INF,4,0},
{0,0,0,INF,0},
{0,0,0,1,INF}};
int startNode = 1;
dijkstra(W,verticies,startNode-1);
}
public static void dijkstra(int G[][],int n,int startnode)
{
int INF = Integer.MAX_VALUE, nINF = Integer.MIN_VALUE;
//int cost[MAX][MAX],distance[MAX],pred[MAX];
//int visited[MAX],count,mindistance,nextnode,i,j;
int cost[][] = new int[n][n];
int distance[] = new int[n];
int pred[] = new int[n];
boolean visited[] = new boolean[n];
int count=0, mindistance=0, nextnode=0,i,j;
//pred[] stores the predecessor of each node
//count gives the number of nodes seen so far
//create the cost matrix
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(G[i][j]==0)
cost[i][j]=INF;
else
cost[i][j]=G[i][j];
//initialize pred[],distance[] and visited[]
for(i=0;i<n;i++)
{
distance[i]=cost[startnode][i];
pred[i]=startnode;
visited[i]=false;
}
distance[startnode]=0;
visited[startnode]=true;
count=1;
while(count<n-1)
{
mindistance=INF;
//nextnode gives the node at minimum distance
for(i=0;i<n;i++)
if(distance[i]<mindistance&&!visited[i])
{
mindistance=distance[i];
nextnode=i;
}
//check if a better path exists through nextnode
visited[nextnode]=true;
for(i=0;i<n;i++)
if(!visited[i])
if(mindistance+cost[nextnode][i]<distance[i])
{
distance[i]=mindistance+cost[nextnode][i];
pred[i]=nextnode;
}
count++;
}
//print the path and distance of each node
for(i=0;i<n;i++)
if(i!=startnode)
{
if(distance[i] == INF || distance[i] < 0){
System.out.print("\nNo edge exists between node "+(startnode+1)+" and node "+(i+1));
} else {
System.out.format("\nDistance of node %d = %d", (i + 1), distance[i]);
System.out.format("\nPath = %d", (i + 1));
j = i;
do {
j = pred[j];
System.out.format("<-%d", (j + 1));
} while (j != startnode);
}
}
}
I don’t know exactly how, but you are somehow getting INF into your calculations. My suspicion goes to the line distance[i]=mindistance+cost[nextnode][i];, but it may not be the only culprit, I have not checked. When mindistance is 1 (or greater) and cost is Integer.MAX_VALUE, you get an arithmetic overflow and the result gets negative. Further behaviour, I have not predicted, but it’s not as expected.
When in the two places you define INF I change the value to 1,000,000, I get the following output from your program:
Distance of node 2 = 6
Path = 2<-3<-1
Distance of node 3 = 4
Path = 3<-1
Distance of node 4 = 2
Path = 4<-5<-1
Distance of node 5 = 1
Path = 5<-1
I believe this is correct.
The way I found out? I stuck this statement into the middle of your outer while loop:
System.out.println("count " + count + " nextnode " + nextnode + " mindistance " + mindistance);
When it printed a large negative number, I started suspecting an arithmetic overflow. Until you learn to use a debugger, System.out.println() is your friend for debugging.

Need help developing a proper print method for this Java program

This program takes integers from user input and puts them in a collection. It then prints the positive values first, then the negative values, and doesn't print repeated numbers. It stops asking for input once the user enters 0. Here is the code:
public class Intcoll2
{
private int[] c;
private int[] d;
private int howmany = 0;
public Intcoll2()
{
c = new int[500];
}
public Intcoll2(int i)
{
c = new int[i]
}
public void insert(int i)
{
if (i > 0)
{
int j = 0;
while ((j <= howmany) && (c[j] != i)) j++;
if (j == howmany)
{
if (j == c.length - 1)
{
d = new int[2*c.length];
for (int k = 0; k<c.length; i++){
d[k] = c[k];
}
c = d;
}
c[j] = i; c[j + 1] = 0;
}
howmany++;
}
}
public int get_howmany()
{
int j=0, howmany=0;
while (c[j]!=0) {howmany++; j++;}
return howmany;
}
Now my current print method looks like this:
public void print()
{
int j = 0;
System.out.println();
while (j <= howmany)
{
System.out.println(c[j]); j++;
}
}
But when I try to use that in my client, it only prints out zeros. Any help with what I'm doing wrong would be greatly appreciated.
An answer that you were probably not looking for, but still on the only real answer you should care about.
Your problem is not that somewhere in that code a bug is hiding. The problem is that your code is confusing beyond limits:
Dont use single-character variable names.
The constructor that takes an int ... creates an empty array!
Dont say "collection" when you are using arrays.
Dont give fields and local variables the same name.
Seriously: understanding this mess is mainly complicated and hard because you wrote code that is hard to read.
Now you are asking other people to debug such complicated code that you (the author who created it!) do not understand in the first place.
Instead, you might throw this whole thing away. And slowly write it again; but in a way that isn't at all confusing to the reader.
I took a look at your class and rewrote it in a more legible manner. I didn't test it but I'm confident it works. You can check it out and hopefully understand what's happening. Hope this helps!
public class IntCollection2 {
private int[] collection; // A large allocation, not neccessarily filled up.
private int currentSize; // The number of spots currently filled in the collection.
public IntCollection2() {
collection = new int[500];
currentSize = 0;
}
public IntCollection2(int size) {
collection = new int[size];
currentSize = 0;
}
/**
* Inserts a new element into the internal array. If the current array is filled up,
* a new array double the size of the current one is allocated.
* #param element An int to insert into the collection. Must not be '0'.
* #return True if the element was successfully inserted, false if the element was
* equal to '0' and was ignored.
*/
public boolean insert(int element) {
if (element != 0) {
if (currentSize < collection.length - 1) {
collection[currentSize] = element;
} else {
int[] newCollection = new int[collection.length * 2];
for (int i = 0; i < currentSize; i++) {
newCollection[i] = collection[i];
}
newCollection[currentSize] = element;
collection = newCollection;
}
currentSize++;
return true;
} else {
return false;
}
}
/**
* Not actually necessary because the class automatically updates its currentSize
* every time a new element is inserted.
* #return The current number of filled spots in the internal array.
*/
public int getCurrentSize() {
int size = 0;
for (int i = 0; i < collection.length && collection[i] != 0; i++) {
size++;
}
return size;
}
/**
* Prints out all the elements currently in the collection, one on each line.
*/
public void print() {
System.out.println();
for (int i = 0; i < currentSize; i++) {
System.out.println(collection[i]);
}
}
}
FYI: this class just prints out every element in the collection, in order. You mentioned something about printing positive then negative values, but I leave that to you.
EDIT: I'm guessing you're brand new to programming, so I just want to clarify exactly what a collection is. An array is an ordered list of elements. When you create an array, the computer sets aside a bit of memory to hold exactly the number of elements you told it to. You cannot change the size of an existing array. A collection is basically a wrapper around an array. It makes a bigger array than it needs to hold its elements, and when its array becomes full, it allocates a new, bigger one that can hold more elements.

Categories