i am trying to find a path in between two nodes(sourcenode and targetnode). i came up with this code but i cant seem to make it recursively find a path. i even set the nodes to null if the target node is found but i keep getting a stack overflow error.
public void findPathBetween(Node sourceNode, Node targetNode){
//find a path between the sourceNode and targetNode
//select the nodes and edges along the path if one exists.
ArrayList<Node> nodesToSearch = new ArrayList<Node>();
nodesToSearch.add(sourceNode);
//basis
if(sourceNode == null || targetNode == null) return;
//recursion
ArrayList<Node> newNodesToSearch = new ArrayList<Node>(); //get nodes for next level to search
for(Node aNode : nodesToSearch) {
for (Node neighbour : aNode.getNeighbours()) {
if (neighbour != targetNode && newNodesToSearch.isEmpty()) {
newNodesToSearch.add(neighbour);
neighbour.setSelected(true);
edgeBetween(aNode, neighbour).setSelected(true);
sourceNode = neighbour;
}
if (neighbour == targetNode) {
sourceNode = null;
targetNode = null;
return;
}
}
}
if(sourceNode != null &&targetNode != null) {
findPathBetween(sourceNode, targetNode);
}
}
You are storing the state inside the recursion function, and don't pass it to the next iteration. Thus you are simply running one function over and over without changing its arguments and the state that affects its execution.
I do not want to correct your code because I would have to guess you intents in order to provide a good explanation.
Anyway I think that you were trying to implement DFS, so I suggest you to take a look at some working implementations. Just google them, there are plenty, e.g. this one comes with a piece of theory, is simple, and was written by Robert Sedgewick, so it can be trusted.
Related
I have made 4 different traversals for my binary search tree. I am stuck at the last one which is the level order traversal and I can't get seem to find out how to do it correctly.
The main problem is that I don't know how to only search one level at a time, I only can figure out how to search either the whole left or whole right subtree.
private void preOrder(BinaryNode<AnyType> t )
{
if(isEmpty()){
System.out.println("Empty");
}
if(t != null) {
System.out.println(t.element);
preOrder(t.left);
preOrder(t.right);
}
}
private void postOrder(BinaryNode<AnyType> t){
if(isEmpty()){
System.out.println("Empty");
}
if (t != null) {
postOrder(t.left);
postOrder(t.right);
System.out.println(t.element);
}
}
private void inOrder(BinaryNode<AnyType> t)
{
if(isEmpty()){
System.out.println("Empty");
}
if (t != null) {
inOrder(t.left);
System.out.println(t.element);
inOrder(t.right);
}
}
private void levelOrder(BinaryNode<AnyType> t, int level)
{
if(isEmpty()){
System.out.println("Empty");
}
if(height(t) == 2) {
System.out.println(t.element);
}else if(height(t) > 1){
levelOrder(t.left, level );
levelOrder(t.right, level );
}
}
This is how I did it.
private void levelOrder(BinaryNode root) {
if (root == null) {
return;
}
Queue<BinaryNode> q = new LinkedList<>();
// Pushing root node into the queue.
q.add(root);
// Executing loop till queue becomes
// empty
while (!q.isEmpty()) {
BinaryNode curr = q.poll();
System.out.print(curr.element + " ");
// Pushing left child current node
if (curr.left != null) {
q.add(curr.left);
}
// Pushing right child current node
if (curr.right != null) {
q.add(curr.right);
}
}
}
Your approach looks like DFS approach It may not follow that approach.
Try to use Queue here it will help you traverse correctly.
Because it will follow BFS approach so that you can traverse level by level.
Add first left node then right node and according follow.
View the entire search as a sequence of "rounds", one "round" for each level.
In each round :
- initialize a "next round" list of nodes to empty
- process a prepared list of nodes (the ones that are at that level and thus to be searched in that round) whereby for each node :
- do the actual comparison
- add all the node's child nodes to the "next round" list
Start the process with a "next round" list populated with just the root node.
Repeat until the list of "next round" nodes comes up empty or you found what you were looking for.
I am confused about changing the parent of a node in the A* algorithm.
There seem to be different ways of choosing a new parent:
In this video:
https://www.youtube.com/watch?v=KNXfSOx4eEE
It says that you should check this:
G cost currentNode + movement cost from currentNode <= G cost openListNode
If that is the case then we should replace the parent node of the openListNode to the current node.
But in this implementation:
http://www.codebytes.in/2015/02/a-shortest-path-finding-algorithm.html
it has the following code:
static void checkAndUpdateCost(Cell current, Cell t, int cost){
if(t == null || closed[t.i][t.j])return;
int t_final_cost = t.heuristicCost+cost;
boolean inOpen = open.contains(t);
if(!inOpen || t_final_cost<t.finalCost){
t.finalCost = t_final_cost;
t.parent = current;
if(!inOpen)open.add(t);
}
}
It checks the final cost which is : G + H , which contradicts the other explanation, as it should be only G cost, not the sum of the G cost and the heuristic.
Can someone explain me, which one is correct ?, is the implementation wrong ?
Bottom Line Up Front (BLUF):
The video is accurate, but here's the key: The node's parent should only be updated in one of the following two cases: 1.) when encountering the node for the first time, or 2.) when you find a more efficient path to a node that was previously encountered. Also, do not use the heuristic when updating a node's parent.
Additional Details:
Below is a working implementation based on Wikipedia's Pseudocode; I've added extra comments to differentiate the two cases.
If !isOpen && !isClosed is true then the node has never been seen before; therefore, it's parent should be set to the current node, and it should be added to the open set. But if !isOpen && !isClosed is false, then the node was already in the open set (i.e. if isOpen is true) or if it was previously closed (i.e. if isClosed is true). Therefore, we need to check if the current path is more efficient than the one which previously caused the neighbor node to be in the open/closed set-- this is why we check if costFromStart < g_score[neighborNode.x][neighborNode.y]
while (!openList.isEmpty()) {
Pair node = openList.dequeueMin().getValue();
if (node.equals(goal)) {
// construct the path from start to goal
return reconstruct_path(goal);
}
for (Pair neighborNode : getNeighbors(node,goal)) {
if (neighborNode == null) continue;
boolean isOpen = openSet.contains(neighborNode);
boolean isClosed = closedSet.contains(neighborNode);
double costFromStart = g_score[node.x][node.y]+MOVEMENT_COST;
// check if the neighbor node has not been
// traversed or if a shorter path to this
// neighbor node is found.
if (
(!isOpen && !isClosed) // first time node has been encountered
|| //or
costFromStart < g_score[neighborNode.x][neighborNode.y]) //new path is more efficient
{
came_from[neighborNode.x][neighborNode.y] = node;
g_score[neighborNode.x][neighborNode.y] = costFromStart;
h_score[neighborNode.x][neighborNode.y] =
estimateCost(neighborNode,goal);
if (isClosed) {
closedSet.remove(neighborNode);
}
if (!isOpen) {
openList.enqueue(neighborNode,costFromStart);
openSet.add(neighborNode);
}
}
}
closedSet.add(node);
}
I'm pretty new to Java so bear with me. I've got a small bit of code that
checks to see if a currentNode has a property of "fileReference" and returns its value.
Except it doesn't seem like my null check is working because if nothing is in fileReference
I get an error. If a reference to fileReference exists it works fine. Here is the error:
Caused by: javax.jcr.PathNotFoundException: fileReference
Here is my code:
if(currentNode != null){
NodeIterator checkNode = currentNode.getNodes();
while (checkNode.hasNext()) {
Node imageNode = checkNode.nextNode();
printNodeTitle = imageNode.getProperty("fileReference").getString();
}
}
public String getImageNode() { (printNodeTitle != null) ? return printNodeTitle : return ""; }
Any help is greatly appreciated!
I'm pretty confident fileReference is actually a property, not a seperate node (since you are calling properties). Since you know the name of the property you want to get, I suggest getting it directly with a small check if it exists.
if(currentNode != null){
NodeIterator checkNode = currentNode.getNodes();
while (checkNode.hasNext()) {
Node imageNode = checkNode.nextNode();
if(imageNode.hasProperty("fileReference")){
Property fileReferenceProp = imageNode.getProperty("fileReference");
printNodeTitle = fileReferenceProp.getString();
}
}
}
I'm assuming you deal with possible repository exceptions elsewhere
I'm not an expert on sling but try this
if(currentNode != null){
NodeIterator checkNode = currentNode.getNodes();
while (checkNode.hasNext()) {
Node imageNode = checkNode.nextNode();
Iterator<Node> fileReferences = imageNode.getProperties("fileReference");
if(fileReferences.hasNext()) { // You might want to improve this
printNodeTitle = fileReference.next().getString(); // You might want to improve it
}
}
}
You retrieve all nodes with getProperties(String), if no nodes are found and empty Iterator is retrieved.
The line Node fileReference... I just guessed the type (Node) you must change it.
I have developed a code to merge two already sorted linked lists in java.
I need help with the following:
How do I retain the value of head node of merged list without using tempNode?
Can this code be better optimized?
public static ListNode mergeSortedListIteration(ListNode nodeA, ListNode nodeB) {
ListNode mergedNode ;
ListNode tempNode ;
if (nodeA == null) {
return nodeB;
}
if (nodeB == null) {
return nodeA;
}
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode = nodeA;
nodeA = nodeA.getNext();
}
else
{
mergedNode = nodeB;
nodeB = nodeB.getNext();
}
tempNode = mergedNode;
while (nodeA != null && nodeB != null)
{
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode.setNext(nodeA);
nodeA = nodeA.getNext();
}
else
{
mergedNode.setNext(nodeB);
nodeB = nodeB.getNext();
}
mergedNode = mergedNode.getNext();
}
if (nodeA != null)
{
mergedNode.setNext(nodeA);
}
if (nodeB != null)
{
mergedNode.setNext(nodeB);
}
return tempNode;
}
1: You have to keep a record of the first node, which means you will have to store it in a variable such as tempNode.
2: No. There's not much to optimize here. The process is quite trivial.
There are a few possibilities:
1) Instead of using mergedNode to keep track of the previous node, use nodeA.getNext().getValue() and nodeB.getNext().getValue(). Your algorithm will become more complex and you will have to deal with a few edge cases, but it is possible to eliminate one of your variables.
2) Use a doubly linked-list, and then use either nodeA.getPrev().getValue() and nodeB.getPrev().getValue() instead of mergedNode. You will also have to deal with edge cases here too.
In order to deal with edge cases, you will have to guarantee that your references can not possibly be null before calling getPrev(), getNext() or getValue(), or else you will throw an exception.
Note that the above modifications sacrifice execution time slightly and (more importantly) simplicity in order to eliminate a variable. Any gains would be marginal, and developer time is far more important than shaving a microsecond or two off of your operation.
I need to make a method that removes the last element of a LinkedList using recursion.
This is what I have so far but it doesn't seem to be removing the node...when i call list.size() it is still the same size with the same values. What am I doing wrong here?
This is for Java by the way
public void removeLastElement(Node curr){
if (curr == null)
return;
else{
if(curr.next == null)
curr = null;
else
removeLastElement(curr.next);
}
}
In a LinkedList to remove the last element you have to get the penultimate element and set
curr.next = null
You're in the right way to get the recurrent function to remove the last node. The problem is you're identifying the penultimate node with curr.next == null, if you got it, you nullify it, but that's your actual input! So, you must check if the actual node is the antepenultimate node on the list:
if (curr.next.next == null) {
curr.next = null; //Now you're modifying the data in your input.
}
With this change, there are more basic cases to check, but that's up to you, my friend.
Boolean deleteLast(Node n)
{
if(n.next == null)
return true;
if(deleteLast(n.next))
{
n.next = null;
return false;
}
return false;
}
Node deleteLast(Node n) {
if (n.next == null)
return null;
n.next = deleteLast(n.next);
return this;
}
The general idea is you ask the next node "hey, can you tell me where you are, and delete your last node?" The last node can then just say "I'm nowhere" and it'll all fall into place.
This is very similar to Aadi's answer, just using Nodes instead of booleans.