I want to implement dfs for nodes that are of type long in Java.
My algorithm calculates correctly the number of nodes, and the number
of edges, but not the sequence of nodes. Could you please help me
modify my algorithm so I calculate the order in which the nodes are
visited, correctly?
This is my code:
private int getNumberOfNodes(long firstNode) {
List<Long> marked = new ArrayList<>(); //------------------------------------------->
Stack<Long> stack = new Stack<Long>(); //step 1 Create/declare stack
stack.push(firstNode); //Step 2 Put/push inside the first node
while (!stack.isEmpty()) { //Repeat till stack is empty:
Long node = stack.pop(); //Step 3 Extract the top node in the stack
marked.add(node); //------------------------------------------->
long[] neighbors = xgraph.getNeighborsOf(node); //Get neighbors
if (neighbors.length % 2 == 0) {
} else {
numOfNodesWithOddDegree++;
}
int mnt = 0;
for (long currentNode : neighbors) {
if (!marked.contains(currentNode) && !stack.contains(currentNode) ) { //&& !stack.contains(currentNode)
stack.push(currentNode);
} else {
}
if (!marked.contains(currentNode)) {
numOfEdges++;
}
}
}
return marked.size(); //(int) Arrays.stream(neighbors).count();
}
I guess you exam the marked list for the sequence.
As your graph is undirected, the sequence of traversals could be varied based on which neighbor you pushed into the stack first. which means the logic of your function:
xgraph.getNeighborsOf(node)
could impact your sequence. see Vertex orderings from this wiki https://en.wikipedia.org/wiki/Depth-first_search
so my conclusion is: you may have a different traversal sequence, it does not mean your DFS is wrong, as long as it is Deep first search, it is ok to be a little bit different from the given answer.
Related
I was tasked to perform the Dijkstra Algorithm on big graphs (25 million nodes). These are represented as a 2D array: -each node as a double[] with latitude, longitude and offset (offset meaning index of the first outgoing edge of that node)
-each edge as a int[] with sourceNodeId,targetNodeId and weight of that edge
Below is the code, I used int[] as a tupel for the comparison in the priority queue.
The algorithm is working and gets the right results HOWEVER it is required to be finished in 15s but takes like 8min on my laptop. Is my algorithm fundamentally slow? Am I using the wrong data structures? Am I missing something? I tried my best optimizing as far as I saw fit.
Any help or any ideas would be greatly appreciated <3
public static int[] oneToAllArray(double[][]nodeList, int[][]edgeList,int sourceNodeId) {
int[] distance = new int[nodeList[0].length]; //the array that will be returned
//the priorityQueue will use arrays with the length 2, representing [index, weight] for each node and order them by their weight
PriorityQueue<int[]> prioQueue = new PriorityQueue<>((a, b) -> ((int[])a)[1] - ((int[])b)[1]);
int offset1; //used for determining the amount of outgoing edges
int offset2;
int newWeight; //declared here so we dont need to declare it a lot of times later (not sure if that makes a difference)
//currentSourceNode here means the node that will be looked at for OUTGOING edges
int[] currentSourceNode= {sourceNodeId,0};
prioQueue.add(currentSourceNode);
//at the start we only add the sourceNode, then we start the actual algorithm
while(!prioQueue.isEmpty()) {
if(prioQueue.size() % 55 == 2) {
System.out.println(prioQueue.size());
}
currentSourceNode=prioQueue.poll();
int sourceIndex = currentSourceNode[0];
if(sourceIndex == nodeList[0].length-1) {
offset1= (int) nodeList[2][sourceIndex];
offset2= edgeList[0].length;
} else {
offset1= (int) nodeList[2][sourceIndex];
offset2= (int) nodeList[2][sourceIndex+1];
}
//checking every outgoing edge for the currentNode
for(int i=offset1;i<offset2;i++) {
int targetIndex = edgeList[1][i];
//if the node hasnt been looked at yet, the weight is just the weight of this edge + distance to sourceNode
if(distance[targetIndex]==0&&targetIndex!=sourceNodeId) {
distance[targetIndex] = distance[sourceIndex] + edgeList[2][i];
int[]targetArray = {targetIndex, distance[targetIndex]};
prioQueue.add(targetArray);
} else if(prioQueue.stream().anyMatch(e -> e[0]==targetIndex)) {
//above else if checks if this index is already in the prioQueue
newWeight=distance[sourceIndex]+edgeList[2][i];
//if new weight is better, we have to update the distance + the prio queue
if(newWeight<distance[targetIndex]) {
distance[targetIndex]=newWeight;
int[] targetArray;
targetArray=prioQueue.stream().filter(e->e[0]==targetIndex).toList().get(0);
prioQueue.remove(targetArray);
targetArray[1]=newWeight;
prioQueue.add(targetArray);
}
}
}
}
return distance;
}
For each node that you process, you are doing a linear scan of the priority queue to see if something is already queued, and a second scan to find all the things that are queued if you have to update the distance. Instead, keep a separate multi-set of things that are in the queue.
This is not a proper Dijkstra's implementation.
One of the key elements of Dijkstra is that you mark nodes as "visited" when they have been evaluated and prevent looking at them again because you can't do any better. You are not doing that, so your algorithm is doing many many more computations than necessary. The only place where a priority queue or sort is required is to pick the next node to visit, from amongst the unvisited. You should re-read the algorithm, implement the "visitation tracking" and re-formulate.
I'm in a super trouble. I really don't know how to modify the code to print each cycle that has been found. Actually the code below is returning if the graph contains a cycle, but I also want to know what are all the possible cycles.
For example, the following graph contains three cycles 0->2->0, 0->1->2->0 and 3->3, so your function must return true.
// A Java Program to detect cycle in a graph
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class Graph {
private final int V;
private final List<List<Integer>> adj;
public Graph(int V)
{
this.V = V;
adj = new ArrayList<>(V);
for (int i = 0; i < V; i++)
adj.add(new LinkedList<>());
}
// This function is a variation of DFSUytil() in
// https://www.geeksforgeeks.org/archives/18212
private boolean isCyclicUtil(int i, boolean[] visited, boolean[] recStack)
{
// Mark the current node as visited and
// part of recursion stack
if (recStack[i])
return true;
if (visited[i])
return false;
visited[i] = true;
recStack[i] = true;
List<Integer> children = adj.get(i);
for (Integer c: children)
if (isCyclicUtil(c, visited, recStack))
return true;
recStack[i] = false;
return false;
}
private void addEdge(int source, int dest) {
adj.get(source).add(dest);
}
// Returns true if the graph contains a
// cycle, else false.
// This function is a variation of DFS() in
// https://www.geeksforgeeks.org/archives/18212
private boolean isCyclic()
{
// Mark all the vertices as not visited and
// not part of recursion stack
boolean[] visited = new boolean[V];
boolean[] recStack = new boolean[V];
// Call the recursive helper function to
// detect cycle in different DFS trees
for (int i = 0; i < V; i++)
if (isCyclicUtil(i, visited, recStack))
return true;
return false;
}
// Driver code
public static void main(String[] args)
{
Graph graph = new Graph(4);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 2);
graph.addEdge(2, 0);
graph.addEdge(2, 3);
graph.addEdge(3, 3);
if(graph.isCyclic())
System.out.println("Graph contains cycle");
else
System.out.println("Graph doesn't "
+ "contain cycle");
}
}
Thank you so much.
Edit:
Previously I mentioned the possibility to use dfs instead of bfs,
however using dfs might produce non-minimal cycles. (e.g. if a cycle A->B->C->A exists and a cylce A->B->A exists, it might find the longer one first and it won't find the second one as nodes are only visited once).
As per definition an elementary cycle is one where a node does not repeat itself (besides the starting one), so the case is a bit different. As the questioner (of the bounty #ExceptionHandler) wanted those cycles excluded from the output, using bfs solves that issue.
For a pure (brute-force) elementary cycle search a different path finding algorithm would be required.
A general purpose (aka brute force) implementation would entail the following steps:
For every node n of a directed graph gfind all pathes (using bfs) back to n.If muliple edges between two nodes (with the same direction) exist they can be ignored at this step, as the algorithm itself should work on nodes rather than edges. Multiple edges can be reintroduced into the cycles during step 5.
if no pathes are found, continue in Step 1 with n+1
Every identified path is a cylceadd them to a list of cycles, and continue with Step 1 and n+1
After all nodes have been processed a list containing all possible cycles have been found (including permutations). Subcycles could not have been formed as every node can only be visited once during bfs.In this step all permutations of previously identified are grouped in sets. Only one cylce per set is considered. This can be done by ordering the node and removing duplicates.
Now the minimum set of cycles has been identified and can be printed out.In case you are looking for edge-specific cycles, replace the connection between two nodes with their respective edge(s).
Example for the graph A->B B->C C->D D->C C->A:
Step 1-3: node A
path identified: A,B,C (A->B B->C C->A)
Step 1-3: node B
path identified: B,C,A (B->C C->A A->B)
Step 1-3: node C
path identified: C,A,B (C->A A->B B->C)
path identified: C,D (C->D D->C)
Step 1-3: node D
path identified: D,C (D->C C->D)
Step 4:
Identified as identical after ordering:
Set1:
A,B,C (A->B B->C C->A)
B,C,A (B->C C->A A->B)
C,A,B (C->A A->B B->C)
Set2:
C,D (C->D D->C)
D,C (D->C C->D)
Therefore remaining cycles:
A,B,C (A->B B->C C->A)
C,D (C->D D->C)
Step 5:
Simply printing out the cycles
(Check the bracket expressions for that,
I simply added them to highlight the relevant edges).
A more efficient sample implementation to identify elementary cycles can be found here, which was directly taken from this answer. If someone wants to come up with a more detailed explanation how that algorithm works exactly feel free to do so.
Modifing the main method to:
public static void main(String[] args) {
String nodes[] = new String[4];
boolean adjMatrix[][] = new boolean[4][4];
for (int i = 0; i < 4; i++) {
nodes[i] = String.valueOf((char) ('A' + i));
}
adjMatrix[0][1] = true;
adjMatrix[1][2] = true;
adjMatrix[2][3] = true;
adjMatrix[3][2] = true;
adjMatrix[2][0] = true;
ElementaryCyclesSearch ecs = new ElementaryCyclesSearch(adjMatrix, nodes);
List cycles = ecs.getElementaryCycles();
for (int i = 0; i < cycles.size(); i++) {
List cycle = (List) cycles.get(i);
for (int j = 0; j < cycle.size(); j++) {
String node = (String) cycle.get(j);
if (j < cycle.size() - 1) {
System.out.print(node + " -> ");
} else {
System.out.print(node + " -> " + cycle.get(0));
}
}
System.out.print("\n");
}
}
leeds to the desired output of:
A -> B -> C -> A
C -> D -> C
Donald B. Johnson paper that describes the approach in more detail can be found here.
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.
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);
}
}
So I wrote a Graph class and I can't seem to do a depth first search on it properly depending on the sequencing of nodes. Here's what I mean:
If my graph looks like this:
A-B-D
|/
C
The DFS returns: "ABC"
But when it looks like this:
A-B
| |
D C
|
E
It will print ABCDE correctly.
The problem I've found lies in my getUnvisitedAdjacentNode() function. Here is the function:
public int getUnvisitedAdjacentNode(int n) {
for (int i = 0; i < this.nodeList.size(); i++) {
if (this.edges[n][i] == 1 && this.nodeList.get(i).wasVisited == false) {
return i;
}
}
return -1;
}
The problem, I've found is because it goes in "order" (just a for loop) , it will never get traverse D in the first situation because B gets visited and after C gets visited, B simply get's popped off of the stack. Maybe this isn't the problem.
Here's the code for my actual DFS traversal.
public void depthFirstTraverse() {
Stack<Node> stack = new Stack<Node>();
nodeList.get(0).wasVisited = true;
System.out.println(nodeList.get(0).item);
stack.push(nodeList.get(0));
while (!stack.isEmpty()) {
int nextNode = this.getUnvisitedAdjacentNode(stack.peek().index);
if (nextNode == -1) {
stack.pop();
} else {
nodeList.get(nextNode).wasVisited = true;
System.out.println(nodeList.get(nextNode).item);
stack.push(nodeList.get(nextNode));
}
}
for (int i = 0; i < nodeList.size(); i++) {
nodeList.get(i).wasVisited = false;
}
}
Fortunately I found my own mistake, the code above is all correct, except it was in the code that I hadn't pasted.
In case anybody cares, the problem lied in the fact that I completely disregarded the fact that ArrayLists have an "IndexOf()" method (stupid, I know) and decided to hack my own "index" field into my Node class. When dealing with my own indices, I had a minor bug which screwed up the traversal.
So the old line in my DFS algorithm looks like this:
int nextNode = this.getUnvisitedAdjacentNode(stack.peek().index);
But it should be:
int nextNode = this.getUnvisitedAdjacentNode(this.nodeList.indexOf(stack.peek()));
You said it. If you pop a node off of the stack, you need to make sure that all of its unvisited neighbors are on the stack first. Otherwise, there's no guarantee that everyone will be visited.
For example, in the first diagram you gave, if node A is visited first, and then node B, either node C or D will be visited next. However, if you only push one of them onto the stack, and then remove B, there will be no way of reaching the last one.
So what you may want to do it write a function getAllUnvisitedAdjacentNodes and push all of them onto the stack before you pop.