so I have a list of basic nodes, for example nodes A B C.
each component can see what it is attached to for example:
a->b
b->c
c->a
I want a way that I can get a list of all the nodes in the graph. However, I'm running into trouble as my current system can't detect if it has already reached a point. EG in the above example it will go a->b->c->a->b etc. How can I detect this or how can I solve this problem.
My current "solution" getList() in the Node class:
ArrayList<Node> tempList = new ArrayList<Node>();
tempList.add(this);
for(int i = 0 ; i < nodesAttachedTo.size();i++){
tempList.addAll(nodesAttachedTo.get(i).getList());
}
return tempList;
You can use a HashSet. It will not allow one element to be added twice.
Here's an example code that first creates the graph similar to your example, then starts at some point in the graph and goes through it.
import java.util.HashSet;
public class Node
{
private HashSet<Node> nextNodes = new HashSet<Node>();
public Node()
{
}
public void addNextNode(Node node)
{
nextNodes.add(node);
}
public static void main(String[] args)
{
// this builds the graph of connected nodes
Node a = new Node();
Node b = new Node();
Node c = new Node();
a.addNextNode(b);
b.addNextNode(c);
c.addNextNode(a);
//this is the set that will lsit all nodes:
HashSet<Node> allNodes = new HashSet<Node>();
// this goes through the graph
a.listAllNodes(allNodes);
System.out.println(allNodes);
}
private void listAllNodes (HashSet<Node> listOfNodes)
{
// try to put all next nodes of the node into the list:
for(Node n : nextNodes)
{
if (listOfNodes.add(n)) // the set returns true if it did in fact add it.
n.listAllNodes(listOfNodes); // recursion
}
}
}
This goes from one node to all the nodes this node knows. (say that really fast three times)
Until it hits a dead end (= a node it already visited)
I chose to use a HashSet in the Node itself to store all the nodes it knows.
This could also be an ArrayList or whatever. But as I don't think there should be a connection twice, a HashSet seems to be a good choice in this situation, too.
I'm not familiar with your notation, but you could use two pointers to solve your issue. Start with two pointers that point to the same node. Increment one pointer until it returns to the start. Some pseudocode is below.
ArrayList<Node> tempList = new ArrayList<Node>();
Node head = nodesAttachedTo.get(0); //get the head of the list
tempList.add(head);
Node runner = head;
runner = runner.next;
while (!runner.equals(head)) {
tempList.add(runner);
runner = runner.next;
}
A hashmap is probably the way to go here. It allows constant time access (some overhead required, but I'm assuming you want a solution that scales well) to any element in the map.
HashMap<String, String> specificSolution = new HashMap<String, String>();
specificSolution.put("a", "b");
specificSolution.put("b", "c");
specificSolution.put("c", "a");
// To get all nodes in the graph
Set<String> nodes = specificSolution.keySet();
I implemented with String here because you don't provide a definition for the Node Class in your question, but it can be easily swapped out.
There are many different ways to represent a graph and each has their own limitations/advantages. Maybe another might be more appropriate but we would need more information about the problem.
Related
I wrote this static method in Python to do breadth first search. However, I mainly use Java, and I want to get a sense of how the data structures convert to Java, given generics, etc. My code is:
def bfs(graph, start_vertex, target_value):
path = [start_vertex] #a list that contains start_vertex
vertex_and_path = [start_vertex, path] #a list that contains start_vertex and path
bfs_queue = [vertex_and_path]
visited = set() #visited defined as an empty set
while bfs_queue: #while the queue is not empty
current_vertex, path = bfs_queue.pop(0) #removes element from queue and sets both equal to that first element
visited.add(current_vertex) #adds current vertex to visited list
for neighbor in graph[current_vertex]: #looks at all neighboring vertices
if neighbor not in visited: #if neighbor is not in visited list
if neighbor is target_value: #if it's the target value
return path + [neighbor] #returns path with neighbor appended
else:
bfs_queue.append([neighbor, path + [neighbor]]) #recursive call with path that has neighbor appended
a graph I'd use this on would be:
myGraph = { //I'm not sure how to structure this in Java
'lava': set(['sharks', 'piranhas']),
'sharks': set(['lava', 'bees', 'lasers']),
'piranhas': set(['lava', 'crocodiles']),
'bees': set(['sharks']),
'lasers': set(['sharks', 'crocodiles']),
'crocodiles': set(['piranhas', 'lasers'])
}
and I would call it like
public static void main(String[] args){
System.out.println(bfs(myGraph, "crocodiles", "bees"));
}
So far, here's the Java I have:
public class BreadthFirstSearch{
///NOT DONE YET
public static ArrayList<String> BFS(Map<String, String[]> graph, String start, String target) {
List<String> path = new ArrayList<>();
path.add(start);
List<String> vertexAndPath = new ArrayList<>();
vertexAndPath.add(start);
vertexAndPath.add(path.get(0));
ArrayList<String> queue = new ArrayList<>();
queue.add(vertexAndPath.get(0));
queue.add(vertexAndPath.get(1));
Set<String> visited = new HashSet<String>();
while(!queue.isEmpty()) {
String currentVertex = queue.remove(0);
String curVerValue = currentVertex;
path.add(currentVertex);
.
.
.
}
}
}
Good effort on the translation. Let me offer my code, then an explanation:
import java.util.*;
class BreadthFirstSearch {
public static ArrayList<String> BFS(
Map<String, String[]> graph, String start, String target
) {
Map<String, String> visited = new HashMap<>();
visited.put(start, null);
ArrayDeque<String> deque = new ArrayDeque<>();
deque.offer(start);
while (!deque.isEmpty()) {
String curr = deque.poll();
if (curr.equals(target)) {
ArrayList<String> path = new ArrayList<>();
path.add(curr);
while (visited.get(curr) != null) {
curr = visited.get(curr);
path.add(curr);
}
Collections.reverse(path);
return path;
}
for (String neighbor : graph.get(curr)) {
if (!visited.containsKey(neighbor)) {
visited.put(neighbor, curr);
deque.offer(neighbor);
}
}
}
return null;
}
public static void main(String[] args) {
Map<String, String[]> myGraph = new HashMap<>();
myGraph.put(
"lava", new String[] {"sharks", "piranhas"}
);
myGraph.put(
"sharks", new String[] {"lava", "bees", "lasers"}
);
myGraph.put(
"piranhas", new String[] {"lava", "crocodiles"}
);
myGraph.put(
"bees", new String[] {"sharks"}
);
myGraph.put(
"lasers", new String[] {"sharks", "crocodiles"}
);
myGraph.put(
"crocodiles", new String[] {"piranhas", "lasers"}
);
System.out.println(BFS(myGraph, "crocodiles", "bees"));
System.out.println(BFS(myGraph, "crocodiles", "crocodiles"));
System.out.println(BFS(myGraph, "crocodiles", "zebras"));
}
}
Output
[crocodiles, lasers, sharks, bees]
[crocodiles]
null
Explanation
I made the design decision to avoid copying a path ArrayList on every node in the graph in favor of a visited hash that stores nodes in childNode => parentNode pairs. This way, once I've located the destination node, I retrace my steps to create the path in one shot, instead of building a path for every node, most of which ultimately lead nowhere. This is more efficient in space and time; Python makes it too easy to ruin your time complexity with the [] + [] O(n) list concatenation operator.
Using a child => parent visited HashMap is also simpler to code in Java, which doesn't have a light weight Pair/Tuple/struct that can conveniently store different types as nodes in the queue. To do what you're doing in Python in passing a 2-element list into the queue, you'd either have to write your own Pair class, use two ArrayDeques, or avoid generics and use casting, all of which are ugly (especially the last, which is also unsafe).
Another issue I noticed in your code is usage of an ArrayList as a queue. Insertion and removal on the front of a list is a O(n) operation as all elements in the list must be shifted forward or backward in the underlying array to maintain sequencing. The optimal queue structure in Java is an ArrayDeque, which offers O(1) add and removal at both ends and is not thread safe, unlike the Queue collection.
Similarly, in Python, you'll find performance is best using the deque collection which offers a fast popleft operation for all your queuing needs. Additionally, in your Python implementation, each key in your hash points to a set, which is okay, but seems like an unnecessary structure when a list would do (you've switched to a primitive array in Java). If you're not manipulating the graph and only iterating over neighbors, this seems ideal.
Note that this code also presumes that every node has a key in the hash that represents the graph, as your input does. If you plan to input graphs where nodes may not have keys in the hash, you'll want to make sure that graph.get(curr) is wrapped with a containsKey check to avoid crashing.
Another assumption worth mentioning: ensure your graph doesn't contain nulls since the visited hash relies on null to indicate that a child has no parent and is the start of the search.
You would need to create a separate class to hold nodes of a graph. Those nodes could not be static, as they all have unique vertexes. From there the rest is very similar.
public class Node {
public String name;
public ArrayList<Node> vertices;
public void addEdge(Node node) {
edges.add(node);
}
}
I need help writing a method that returns an iterator over all nodes in a graph, according to the order they are encountered in a DFS traversal. The method needs to use a stack and not be recursive.
Iterator<T> dfsNodeListing(T start){
//Where start is the node that the dfs traversal will begin from.
}
I have successor and predecessor set in the form of Hashtables to keep track of the edges going to and from each node. I also have an ArrayList that a node gets added to if it is visited by the search.
private Hashtable <T, Set<T>> pred = new Hashtable<>();
private Hashtable <T, Set<T>> succ = new Hashtable<>();
private ArrayList<T> mark = new ArrayList <>();
How can all of these elements be brought together?
EDIT: This is what I am currently working with. I get caught up somewhere in the middle and the method never completes.
public Iterator<T> dfsNodeListing(T start) {
Stack<T> stk = new Stack<>();
stk.push(start);
if(!mark.contains(start)){
mark.add(start);
stk.push(start);
while(!stk.isEmpty()){
stk.pop();
for(T n : succ.get(start)){
if(!mark.contains(n)){
stk.push(n);
}
}
}
}
return mark.iterator();
}
I think your foreach loop has a problem because you only get successors of start node instead of the node that you popped from the stack. You can modify your code like:
while(!stk.isEmpty()){
for(T n : succ.get(stk.pop())){
if(!mark.contains(n)){
stk.push(n);
mark.add(n);
}
}
}
I know this is a duplicate problem but my question is different.
Help me to understand few lines of this code.It removes duplicate nodes from a single linked list.
public class DeleteDuplicates {
static void deleteDups(LinkedListNode n) {
Hashtable table = new Hashtable();
LinkedListNode previous = null;
while(n!=null) {
if(table.containsKey(n.data)) {
previous.next = n.next;
} else {
table.put(n.data, true);
previous = n;
}
System.out.println(n.next.data);
n = n.next;
}
}
public static void main(String[] args) {
LinkedListNode node_1 = new LinkedListNode("first");
LinkedListNode node_2 = new LinkedListNode("second");
node_1.next = node_2;
LinkedListNode node_3 = new LinkedListNode("third");
node_2.next = node_3;
LinkedListNode node_4 = new LinkedListNode("second");
node_3.next = node_4;
LinkedListNode current = node_1;
deleteDups(current);
while (current != null) {
System.out.println(current.data);
current = current.next;
}
}
}
Questions I have are:
How come LinkedList n is skipping the duplicate node? I didn't understand the use of previous node and how it is helping in skipping the duplicate node.
How important is the use of Hashtable? Can I use any other collection for example HashSet?
You already have good answers to your question 2, so I'll just concentrate on question 1 (really you should only ask 1 question in each post, by the way). This is how the removal of the duplicate works:
In each iteration through your loop, previous holds a reference to the node in the list before the node n. So, when n is set to your node_4, previous is set to node_3. Therefore, previous.next = n.next is equivalent to node_3.next = node_4.next, which because you don't set a value for node_4.next is equivalent to node_3.next = null, which has the effect of making node_3 the last node in the list, thus removing node_4 from the list.
If, instead of node_4 being the duplicate, it was node_3 that was duplicated, then previous would be node_2, n would be node_3 and the change made would be equivalent to node_2.next = node_3.next, which is to say node_2.next = node_4 or in plain English, "make the next node after node_2 be node_4", effectively removing node_3 from the list.
1) LinkedList is not skipping the duplicate node, it is being mapped out - next is pointed to the entry after the duplicate.
2) Think LinkedList allows duplicates, but Hashtable does not -> make your conclusion from this
You can use any data structure you like for detecting duplicates.
From an implementation point of view, hashes are nice because they take (amortized) constant time to determine whether or not a particular element is a duplicate.
From an API point of view, the Collection.Set interface is nice because it guarantees no duplicate items.
So your idea of using a HashSet seems very intuitive, especially because you're only interested in duplicate keys, without regard for the actual node object.
I have a data structure that looks like this
private String name;
private ArrayList<Node> children;
private String parent="";
public Node(String name) {
setName(name);
children = new ArrayList<Node>();
}
Elsewhere in my program, I have a Node called "root" that contains an entire tree data structure.
Conceptually it looks like this
root
/ \
/ \
node1 node2
/ \
/ \
node2 node3
/
/
node3
As you can see nodes can have the same name. That's intended. I want to create a string for each node that contains its own name, plus it's lineage and store them in a Vector.
so node 3 on the left hand side would be "root|node1|node2|node3" the node3 on the rhs would be "root|node2|node3" node1 would be "root|node1"etc.
I have a way to iterate through the node structure to print each node, but I'm finding it difficult to set every parent, as in, I can't figure out a way to do it. Any help would be fantastic as everything I've tried so far has failed. One important note is that the tree may not necessarily be a Binary tree, I'm just using it for an example.
Here's the code I use for printing every node of the tree. Hopefully it will be easy to tweak.
public void print() {
LinkedList<Node> open = new LinkedList<Node>();
LinkedList<Node> closed = new LinkedList<Node>();
open.add(this);
while(!open.isEmpty()) {
Node currentNode = open.removeFirst();
System.out.println(currentNode.getName());
ArrayList<Node> children = currentNode.getChildren();
closed.add(currentNode);
for(int i = 0; i < children.size(); i++) {
Node current = children.get(i);
open.addLast(current);
}
}
}
Thanks guys.
I'm assuming that you already have these nodes created and they were created with children but without the parent? Seems like there are a few options:
When creating the children, set the parent (I would think you don't really have control over this because you are asking this question) so...
Instead of a Vector maybe use some type of Map where you can set the key as the lineage. Then when you iterate over the nodes do some string tweaking to remove the current node's name and you are left with the parent lineage.
Related to #2, don't use a Map (and keep the Vector) and still do the string manipulation but you would then have to iterate every node in the Vector to look for the parent by its lineage.
Hope this helps and hopefully I assumed correctly
-Dave
it seems that it would be easier to add the parent as you are building the tree but if you have the tree built and want to add a parent to each node you can use recursion.
I'd try something like
addParent(root, "");
public void addParent(Node node, String parent) {
node.setParent(parent);
// if this node has children iterate through them
// and call addParent with current node name.
for(Node childNode : node.getChildren()) {
addParent(childNode, node.getName());
}
}
NOTE: I was not able to test this code before posting.
I'm trying build a method which returns the shortest path from one node to another in an unweighted graph. I considered the use of Dijkstra's but this seems a bit overkill since I only want one pair. Instead I have implemented a breadth-first search, but the trouble is that my returning list contains some of the nodes that I don't want - how can I modify my code to achieve my goal?
public List<Node> getDirections(Node start, Node finish){
List<Node> directions = new LinkedList<Node>();
Queue<Node> q = new LinkedList<Node>();
Node current = start;
q.add(current);
while(!q.isEmpty()){
current = q.remove();
directions.add(current);
if (current.equals(finish)){
break;
}else{
for(Node node : current.getOutNodes()){
if(!q.contains(node)){
q.add(node);
}
}
}
}
if (!current.equals(finish)){
System.out.println("can't reach destination");
}
return directions;
}
Actually your code will not finish in cyclic graphs, consider graph 1 -> 2 -> 1. You must have some array where you can flag which node's you've visited already. And also for each node you can save previous nodes, from which you came. So here is correct code:
private Map<Node, Boolean>> vis = new HashMap<Node, Boolean>();
private Map<Node, Node> prev = new HashMap<Node, Node>();
public List getDirections(Node start, Node finish){
List directions = new LinkedList();
Queue q = new LinkedList();
Node current = start;
q.add(current);
vis.put(current, true);
while(!q.isEmpty()){
current = q.remove();
if (current.equals(finish)){
break;
}else{
for(Node node : current.getOutNodes()){
if(!vis.contains(node)){
q.add(node);
vis.put(node, true);
prev.put(node, current);
}
}
}
}
if (!current.equals(finish)){
System.out.println("can't reach destination");
}
for(Node node = finish; node != null; node = prev.get(node)) {
directions.add(node);
}
directions.reverse();
return directions;
}
Thank you Giolekva!
I rewrote it, refactoring some:
The collection of visited nodes doesn't have to be a map.
For path reconstruction, the next node could be looked up, instead of the previous node, eliminating the need for reversing the directions.
public List<Node> getDirections(Node sourceNode, Node destinationNode) {
//Initialization.
Map<Node, Node> nextNodeMap = new HashMap<Node, Node>();
Node currentNode = sourceNode;
//Queue
Queue<Node> queue = new LinkedList<Node>();
queue.add(currentNode);
/*
* The set of visited nodes doesn't have to be a Map, and, since order
* is not important, an ordered collection is not needed. HashSet is
* fast for add and lookup, if configured properly.
*/
Set<Node> visitedNodes = new HashSet<Node>();
visitedNodes.add(currentNode);
//Search.
while (!queue.isEmpty()) {
currentNode = queue.remove();
if (currentNode.equals(destinationNode)) {
break;
} else {
for (Node nextNode : getChildNodes(currentNode)) {
if (!visitedNodes.contains(nextNode)) {
queue.add(nextNode);
visitedNodes.add(nextNode);
//Look up of next node instead of previous.
nextNodeMap.put(currentNode, nextNode);
}
}
}
}
//If all nodes are explored and the destination node hasn't been found.
if (!currentNode.equals(destinationNode)) {
throw new RuntimeException("No feasible path.");
}
//Reconstruct path. No need to reverse.
List<Node> directions = new LinkedList<Node>();
for (Node node = sourceNode; node != null; node = nextNodeMap.get(node)) {
directions.add(node);
}
return directions;
}
You must include the parent node to each node when you put them on your queue. Then you can just recursively read the path from that list.
Say you want to find the shortest path from A to D in this Graph:
/B------C------D
/ |
A /
\ /
\E---------
Each time you enqueue a node, keep track of the way you got here.
So in step 1 B(A) E(A) is put on the queue. In step two B gets dequeued and C(B) is put on the queue etc. Its then easy to find your way back again, by just recursing "backwards".
Best way is probably to make an array as long as there are nodes and keep the links there, (which is whats usually done in ie. Dijkstra's).
Every time through your loop, you call
directions.Add(current);
Instead, you should move that to a place where you really know you want that entry.
It is really no simpler to get the answer for just one pair than for all the pairs. The usual way to calculate a shortest path is to start like you do, but make a note whenever you encounter a new node and record the previous node on the path. Then, when you reach the target node, you can follow the backlinks to the source and get the path. So, remove the directions.add(current) from the loop, and add code something like the following
Map<Node,Node> backlinks = new HashMap<Node,Node>();
in the beginning and then in the loop
if (!backlinks.containsKey(node)) {
backlinks.add(node, current);
q.add(node);
}
and then in the end, just construct the directions list in backwards using the backlinks map.