I am trying to implement a bi-directional graph search. As I understand, I should somehow merge two breadth-first searches, one which starts at the starting (or root) node and one which starts at the goal (or end) node. The bi-directional search terminates when both breadth-first searches "meet" at the same vertex.
Could you provide me with a code example (in Java, if possible) or link with code for the bidirectional graph search?
Assuming you have Nodes like this (in the file Node.java):
import java.util.HashSet;
import java.util.Set;
public class Node<T> {
private final T data; // The data that you want to store in this node.
private final Set<Node> adjacentNodes = new HashSet<>();
// Constructor
public Node(T data) {
this.data = data;
}
// Getters
/*
* Returns the data stored in this node.
* */
public T getData() {
return data;
}
/*
* Returns a set of the adjacent nodes of this node.
* */
public Set<Node> getAdjacentNodes() {
return adjacentNodes;
}
// Setters
/*
* Attempts to add node to the set of adjacent nodes of this node. If it was not previously added, it is added, and
* true is returned. If it was previously added, it returns false.
* */
public boolean addAdjacent(Node node) {
return adjacentNodes.add(node);
}
}
Then the bidirectional search algorithm (defined in the file BidirectionalSearch.java) would look something like this:
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.LinkedList;
public class BidirectionalSearch {
/*
* Returns true if a path exists between Node a and b, false otherwise.
* */
public static boolean pathExists(Node a, Node b) {
// LinkedList implements the Queue interface, FIFO queue operations (e.g., add and poll).
// Queue to hold the paths from Node a.
Queue<Node> queueA = new LinkedList<>();
// Queue to hold the paths from Node a.
Queue<Node> queueB = new LinkedList<>();
// A set of visited nodes starting from Node a.
Set<Node> visitedA = new HashSet<>();
// A set of visited nodes starting from Node b.
Set<Node> visitedB = new HashSet<>();
visitedA.add(a);
visitedB.add(b);
queueA.add(a);
queueB.add(b);
// Both queues need to be empty to exit the while loop.
while (!queueA.isEmpty() || !queueB.isEmpty()) {
if (pathExistsHelper(queueA, visitedA, visitedB)) {
return true;
}
if (pathExistsHelper(queueB, visitedB, visitedA)) {
return true;
}
}
return false;
}
private static boolean pathExistsHelper(Queue<Node> queue,
Set<Node> visitedFromThisSide,
Set<Node> visitedFromThatSide) {
if (!queue.isEmpty()) {
Node next = queue.remove();
Set<Node> adjacentNodes = next.getAdjacentNodes();
for (Node adjacent : adjacentNodes) {
// If the visited nodes, starting from the other direction,
// contain the "adjacent" node of "next", then we can terminate the search
if (visitedFromThatSide.contains(adjacent)) {
return true;
} else if (visitedFromThisSide.add(adjacent)) {
queue.add(adjacent);
}
}
}
return false;
}
public static void main(String[] args) {
// Test here the implementation above.
}
}
Logic:
In normal course, BFS is recursive. But here we cannot have it recursive because if we start with recursion, then it will cover all nodes from one side (start or end) and will only stop if it is not able to find the end or finds the end.
So in order to do a bidirectional search, the logic will be explained with the example below:
/*
Let's say this is the graph
2------5------8
/ |
/ |
/ |
1---3------6------9
\ |
\ |
\ |
4------7------10
We want to find the path between nodes 1 and 9. In order to do this we will need 2 DS, one for recording the path form beginning and other from end:*/
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav = new ArrayList<>();
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> endTrav = new ArrayList<>();
/*Before starting the loop, initialise these with the values shown below:
startTrav --> index=0 --> <1, {1}>
endTrav --> index=0 --> <9, {9}>
Note here that in the HashMap, the key is the node that we have reached and the value is a linkedList containing the path used to reach to that node.
Now inside the loop we will start traversal on startTrav 1st. We will traverse it from index 0 to 0, and while traversing what ever children are there for the node under process, we will add in startTrav. So startTrav will transform like:
startTrav --> index=0 --> <1, {1}>
startTrav --> index=1 --> <2, {1,2}>
startTrav --> index=2 --> <3, {1,3}>
startTrav --> index=3 --> <4, {1,4}>
Now we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4 is present in endTrav's list = 9). The answer is no, so continue loop.
Now do the same from endTrav
endTrav --> index=0 --> <9, {9}>
endTrav --> index=1 --> <8, {9,8}>
endTrav --> index=2 --> <6, {9,6}>
endTrav --> index=3 --> <10, {9,10}>
Now again we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4 is present in endTrav's list = 9,8,6,10). The answer is no so continue loop.
// end of 1st iteration of while loop
// beginning of 2nd iteration of while loop
startTrav --> index=0 --> <1, {1}>
startTrav --> index=1 --> <2, {1,2}>
startTrav --> index=2 --> <3, {1,3}>
startTrav --> index=3 --> <4, {1,4}>
startTrav --> index=4 --> <5, {1,2,5}>
startTrav --> index=5 --> <6, {1,3,6}>
startTrav --> index=6 --> <7, {1,4,7}>
Now again we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4,5,6,7 is present in endTrav's list = 9,8,6,10). The answer is yes. Colission has occurred on node 6. Break the loop now.
Now pick the path to 6 from startTrav and pick the path to 6 from endTrav and merge the 2.*/
Code for this is as below:
class Node<T> {
public T value;
public LinkedList<Node<T>> nextNodes = new LinkedList<>();
}
class Graph<T>{
public HashMap<Integer, Node<T>> graph=new HashMap<>();
}
public class BiDirectionalBFS {
public LinkedList<Node<Integer>> findPath(Graph<Integer> graph, int startNode, int endNode) {
if(!graph.graph.containsKey(startNode) || !graph.graph.containsKey(endNode)) return null;
if(startNode==endNode) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(startNode));
return ll;
}
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav = new ArrayList<>();
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> endTrav = new ArrayList<>();
boolean[] traversedNodesFromStart = new boolean[graph.graph.size()];
boolean[] traversedNodesFromEnd = new boolean[graph.graph.size()];
addDetailsToAL(graph, startNode, startTrav, traversedNodesFromStart, null);
addDetailsToAL(graph, endNode, endTrav, traversedNodesFromEnd, null);
int collision = -1, startIndex=0, endIndex=0;
while (startTrav.size()>startIndex && endTrav.size()>endIndex) {
// Cover all nodes in AL from start and add new
int temp=startTrav.size();
for(int i=startIndex; i<temp; i++) {
recordAllChild(graph, startTrav, i, traversedNodesFromStart);
}
startIndex=temp;
//check collision
if((collision = checkColission(traversedNodesFromStart, traversedNodesFromEnd))!=-1) {
break;
}
//Cover all nodes in AL from end and add new
temp=endTrav.size();
for(int i=endIndex; i<temp; i++) {
recordAllChild(graph, endTrav, i, traversedNodesFromEnd);
}
endIndex=temp;
//check collision
if((collision = checkColission(traversedNodesFromStart, traversedNodesFromEnd))!=-1) {
break;
}
}
LinkedList<Node<Integer>> pathFromStart = null, pathFromEnd = null;
if(collision!=-1) {
for(int i =0;i<traversedNodesFromStart.length && (pathFromStart==null || pathFromEnd==null); i++) {
if(pathFromStart==null && startTrav.get(i).keySet().iterator().next()==collision) {
pathFromStart=startTrav.get(i).get(collision);
}
if(pathFromEnd==null && endTrav.get(i).keySet().iterator().next()==collision) {
pathFromEnd=endTrav.get(i).get(collision);
}
}
pathFromEnd.removeLast();
ListIterator<Node<Integer>> li = pathFromEnd.listIterator();
while(li.hasNext()) li.next();
while(li.hasPrevious()) {
pathFromStart.add(li.previous());
}
return pathFromStart;
}
return null;
}
private void recordAllChild(Graph<Integer> graph, ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> listToAdd, int index, boolean[] traversedNodes) {
HashMap<Integer, LinkedList<Node<Integer>>> record=listToAdd.get(index);
Integer recordKey = record.keySet().iterator().next();
for(Node<Integer> child:graph.graph.get(recordKey).nextNodes) {
if(traversedNodes[child.value]!=true) { addDetailsToAL(graph, child.getValue(), listToAdd, traversedNodes, record.get(recordKey));
}
}
}
private void addDetailsToAL(Graph<Integer> graph, Integer node, ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav,
boolean[] traversalArray, LinkedList<Node<Integer>> oldLLContent) {
LinkedList<Node<Integer>> ll = oldLLContent==null?new LinkedList<>() : new LinkedList<>(oldLLContent);
ll.add(graph.graph.get(node));
HashMap<Integer, LinkedList<Node<Integer>>> hm = new HashMap<>();
hm.put(node, ll);
startTrav.add(hm);
traversalArray[node]=true;
}
private int checkColission(boolean[] start, boolean[] end) {
for (int i=0; i<start.length; i++) {
if(start[i] && end[i]) {
return i;
}
}
return -1;
}
}
A much more neater and easier to understand approach can be though Arrays. We will replace the complex DS :
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>>
with a simple
LinkedList<Node<Integer>>[]
Here, the index of the LL will define the numeric value of the node. So if the node has value 7, then the path to reach 7 will be stored at index 7 in the array. Also we will remove the boolean arrays for finding which path to which element is found as that can be achieved with our linkedList array itself. We will add 2
LinkedList<Node<Integer>>
which will be used for storing the children as in case of level order traversal of tree. Lastly, we for storing the path for traversal from end, we will store it in reverse order, so that while merging, we do not need to reverse the elements from the 2nd array. Code for this goes as below:
class Node<T> {
public T value;
public LinkedList<Node<T>> nextNodes = new LinkedList<>();
}
class Graph<T>{
public HashMap<Integer, Node<T>> graph=new HashMap<>();
}
public class BiDirectionalBFS {
private LinkedList<Node<Integer>> findPathUsingArrays(Graph<Integer> graph, int startNode, int endNode) {
if(!graph.graph.containsKey(startNode) || !graph.graph.containsKey(endNode)) return null;
if(startNode==endNode) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(startNode));
return ll;
}
LinkedList<Node<Integer>>[] startTrav = new LinkedList[graph.graph.size()];
LinkedList<Node<Integer>>[] endTrav = new LinkedList[graph.graph.size()];
LinkedList<Node<Integer>> traversedNodesFromStart = new LinkedList<>();
LinkedList<Node<Integer>> traversedNodesFromEnd = new LinkedList<>();
addToDS(graph, traversedNodesFromStart, startTrav, startNode);
addToDS(graph, traversedNodesFromEnd, endTrav, endNode);
int collision = -1;
while (traversedNodesFromStart.size()>0 && traversedNodesFromEnd.size()>0) {
// Cover all nodes in LL from start and add new
recordAllChild(traversedNodesFromStart.size(), traversedNodesFromStart, startTrav, true);
//check collision
if((collision = checkColission(startTrav, endTrav))!=-1) {
break;
}
//Cover all nodes in LL from end and add new
recordAllChild(traversedNodesFromEnd.size(), traversedNodesFromEnd, endTrav, false);
//check collision
if((collision = checkColission(startTrav, endTrav))!=-1) {
break;
}
}
if(collision!=-1) {
endTrav[collision].removeFirst();
startTrav[collision].addAll(endTrav[collision]);
return startTrav[collision];
}
return null;
}
private void recordAllChild(int temp, LinkedList<Node<Integer>> traversedNodes, LinkedList<Node<Integer>>[] travArr, boolean addAtLast) {
while (temp>0) {
Node<Integer> node = traversedNodes.remove();
for(Node<Integer> child : node.nextNodes) {
if(travArr[child.value]==null) {
traversedNodes.add(child);
LinkedList<Node<Integer>> ll=new LinkedList<>(travArr[node.value]);
if(addAtLast) {
ll.add(child);
} else {
ll.addFirst(child);
}
travArr[child.value]=ll;
traversedNodes.add(child);
}
}
temp--;
}
}
private int checkColission(LinkedList<Node<Integer>>[] startTrav, LinkedList<Node<Integer>>[] endTrav) {
for (int i=0; i<startTrav.length; i++) {
if(startTrav[i]!=null && endTrav[i]!=null) {
return i;
}
}
return -1;
}
private void addToDS(Graph<Integer> graph, LinkedList<Node<Integer>> traversedNodes, LinkedList<Node<Integer>>[] travArr, int node) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(node));
travArr[node]=ll;
traversedNodes.add(graph.graph.get(node));
}
}
Hope it helps.
Happy coding.
Try this:
Graph.java
import java.util.HashSet;
import java.util.Set;
public class Graph<T> {
private T value;
private Set<Graph> adjacents = new HashSet<>();
private Set<String> visitors = new HashSet<>();
public Graph(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void addAdjacent(Graph adjacent) {
this.adjacents.add(adjacent);
}
public Set<Graph> getAdjacents() {
return this.adjacents;
}
public void setVisitor(String visitor) {
this.visitors.add(visitor);
}
public boolean hasVisitor(String visitor) {
return this.visitors.contains(visitor);
}
#Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Value [").append(value).append("] visitors[");
if (!visitors.isEmpty()) {
for (String visitor : visitors) {
sb.append(visitor).append(",");
}
}
sb.append("]");
return sb.toString().replace(",]", "]");
}
}
GraphHelper.java
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class GraphHelper {
// implements singleton pattern
private static GraphHelper instance;
private GraphHelper() {
}
/**
* #return the instance
*/
public static GraphHelper getInstance() {
if (instance == null)
instance = new GraphHelper();
return instance;
}
public boolean isRoute(Graph gr1, Graph gr2) {
Queue<Graph> queue1 = new LinkedList<>();
Queue<Graph> queue2 = new LinkedList<>();
addToQueue(queue1, gr1, "1");
addToQueue(queue2, gr2, "2");
while (!queue1.isEmpty() || !queue2.isEmpty()) {
if (!queue1.isEmpty()) {
Graph gAux1 = queue1.remove();
Iterator<Graph> it1 = gAux1.getAdjacents().iterator();
while (it1.hasNext()) {
Graph adj1 = it1.next();
System.out.println("adj1 " + adj1);
if (adj1.hasVisitor("2"))
return true;
else if (!adj1.hasVisitor("1"))
addToQueue(queue1, adj1, "1");
}
}
if (!queue2.isEmpty()) {
Graph gAux2 = queue2.remove();
Iterator<Graph> it2 = gAux2.getAdjacents().iterator();
while (it2.hasNext()) {
Graph adj2 = it2.next();
System.out.println("adj2 " + adj2);
if (adj2.hasVisitor("1"))
return true;
else if (!adj2.hasVisitor("2"))
addToQueue(queue2, adj2, "2");
}
}
}
return false;
}
private void addToQueue(Queue<Graph> queue, Graph gr, String visitor) {
gr.setVisitor(visitor);
queue.add(gr);
}
}
GraphTest.java
public class GraphTest {
private GraphHelper helper = GraphHelper.getInstance();
public static void main(String[] args) {
GraphTest test = new GraphTest();
test.testIsRoute();
}
public void testIsRoute() {
Graph commonGraph = new Graph<String>("z");
System.out
.println("Expected true, result [" + helper.isRoute(graph1(commonGraph), graph2(commonGraph)) + "]\n");
commonGraph = new Graph<String>("z");
System.out.println("Expected false, result [" + helper.isRoute(graph1(commonGraph), graph2(null)) + "]\n");
}
private Graph graph1(Graph commonGraph) {
Graph main = new Graph<String>("a");
Graph graphb = new Graph<String>("b");
Graph graphc = new Graph<String>("c");
Graph graphd = new Graph<String>("d");
Graph graphe = new Graph<String>("e");
graphb.addAdjacent(graphc);
graphb.addAdjacent(graphe);
if (commonGraph != null)
graphb.addAdjacent(commonGraph);
graphd.addAdjacent(graphc);
graphd.addAdjacent(graphe);
graphd.addAdjacent(main);
main.addAdjacent(graphb);
main.addAdjacent(graphd);
return main;
}
private Graph graph2(Graph commonGraph) {
Graph main = new Graph<String>("f");
Graph graphg = new Graph<String>("g");
Graph graphh = new Graph<String>("h");
Graph graphi = new Graph<String>("i");
Graph graphj = new Graph<String>("j");
graphg.addAdjacent(graphh);
graphg.addAdjacent(graphj);
if (commonGraph != null)
graphg.addAdjacent(commonGraph);
graphi.addAdjacent(graphh);
graphi.addAdjacent(graphj);
graphi.addAdjacent(main);
main.addAdjacent(graphg);
main.addAdjacent(graphi);
return main;
}
}
Defining a GraphNode as the following structure (using standard arrays) and supposing that you can modify the GraphNode structure by adding two flags used to track the visited nodes (to avoid loops):
public class GraphNode {
public Integer value;
public GraphNode[] nodes;
public boolean markedsource = false;
public boolean markedtarget = false;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GraphNode graphNode = (GraphNode) o;
return Objects.equals(value, graphNode.value);
}
}
This is the solution:
boolean found = bidirectionalSearch(source, target);
// .....
private static boolean bidirectionalSearch(GraphNode sourceNode, GraphNode targetNode) {
HashSet<GraphNode> sourceSet = new HashSet<>();
sourceSet.add(sourceNode);
HashSet<GraphNode> targetSet = new HashSet<>();
targetSet.add(targetNode);
return bidirectionalSearch(sourceSet, targetSet, sourceNode, targetNode);
}
private static boolean bidirectionalSearch(Set<GraphNode> sourceSet, Set<GraphNode> targetSet, GraphNode sourceNode, GraphNode targetNode) {
Set<GraphNode> intersection = sourceSet.stream().filter(targetSet::contains).collect(Collectors.toSet());
if (!intersection.isEmpty()) {
System.out.println("intersection found at: " + intersection.iterator().next().value);
return true;
} else if (sourceSet.contains(targetNode) || targetSet.contains(sourceNode)) {
return true;
} else if (sourceSet.isEmpty() && targetSet.isEmpty()) {
return false;
}
sourceSet = sourceSet.stream().flatMap(BidirectionalSearch::getGraphNodeStreamSource)
.collect(Collectors.toSet());
targetSet = targetSet.stream().flatMap(
BidirectionalSearch::getGraphNodeStreamTarget).collect(Collectors.toSet());
return bidirectionalSearch(sourceSet, targetSet, sourceNode, targetNode);
}
private static Stream<GraphNode> getGraphNodeStreamSource(GraphNode n) {
if (n.nodes != null)
return Arrays.stream(n.nodes).filter(b -> {
if (!b.markedsource) {
b.markedsource = true;
return true;
} else {
return false;
}
});
else {
return null;
}
}
private static Stream<GraphNode> getGraphNodeStreamTarget(GraphNode n) {
if (n.nodes != null)
return Arrays.stream(n.nodes).filter(b -> {
if (!b.markedtarget) {
b.markedtarget = true;
return true;
} else {
return false;
}
});
else {
return null;
}
}
This works by expanding the sourceSet and the targetSet for each iteration, by considering adjacent nodes of the sets in input.
Now let's see advantages against a standard BFS (BreadthFirstSearch). If K is the biggest number of each node and the shortest path from the source to the target node is D, it's possible to shorten time complexity from O(k^D) to 2*O(K^(D/2)).
We have to consider also the added space of the two SETs and the time to check the intersection for every iteration.
With a standard BFS, you need a QUEUE that will have in the worst case all k^d elements of the node at the iteration K. In this case we will have two sets of k^d/2.
Related
I'm doing an assignment for an internship, and they gave me a task to create a navigation menu, such as this one down bellow:
. Company
.... About Us
....... Team
.... Mission
. References
.... Client 1
.... Client 2
The whole point of the task is for me to find a way to transform this input into a tree structure and then print it out recursively...
The input is:
ID NAME PARENTID
1; Company; NULL;
2; About Us; 1;
3; Mission; 1;
4; Team; 2;
5; Client1; 7;
6; Client2; 7;
7; References; NULL;
If this was a first parent then children type of input, then the task would be super easy, however I'm stuck and can't seem to understand the algorithm behind it. The whole deal is that References are added at the end, but Client 1 & Client 2 are both children of References...
Here are the codes:
Model class:
// WITH SETTERS AND GETTERS
public class NavLink
{
private String id;
private String name;
private String parentId;
private String isHidden;
private String linkUrl;
}
Triple Linked List Node Class:
public class TLLNode<NavLink>
{
public NavLink element;
public TLLNode<NavLink> parent, sibling, child;
public TLLNode(NavLink elem)
{
this.element = elem;
parent = sibling = child = null;
}
}
Tree class:
public class Tree
{
private TLLNode<NavLink> root;
public Tree(NavLink element) { this.root = new TLLNode(element); }
public TLLNode<NavLink> getRoot() { return this.root; }
public void addChild(TLLNode<NavLink> node, NavLink element)
{
TLLNode<NavLink> insert = new TLLNode<>(element);
if (node.child == null)
node.child = insert;
else
{
if (node.child.element.getName().compareTo(insert.element.getName()) > 0)
insert.sibling = node.child;
else
{
TLLNode<NavLink> tmp = node.child;
while (tmp.sibling != null)
{
if (tmp.sibling.element.getName().compareTo(insert.element.getName()) > 0)
{
insert.sibling = tmp.sibling;
break;
}
tmp = tmp.sibling;
}
tmp.sibling = insert;
}
}
insert.parent = node;
}
public void printTree() { printTreeRecursive(this.root, 0); }
private void printTreeRecursive(TLLNode<NavLink> node, int level)
{
if (node == null)
return;
for (int i=0; i < level-1; i++)
System.out.print("...");
if (node.element.getHidden().equalsIgnoreCase("False"))
System.out.println("." + node.element.getName());
TLLNode<NavLink> tmp = node.child;
while (tmp != null)
{
printTreeRecursive(tmp, level+1);
tmp = tmp.sibling;
}
}
}
And finally the Main class, where the problem is situated:
public class Main
{
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] parts;
List<NavLink> list = new LinkedList<>();
NavLink link = new NavLink("NULL", "/", "/", "True", "/" );
Tree tree = new Tree(link);
for (int i=0; i<n; i++)
{
parts = br.readLine().split(";");
link = new NavLink(parts[0], parts[1], parts[2], parts[3], parts[4]);
list.add(link);
}
/*TLLNode<NavLink> current;
for (NavLink item : links)
{
current = new TLLNode<>(item);
System.out.println(item);
for (NavLink tmp : links.subList(1, links.size()))
{
if (tmp.getParentId().equalsIgnoreCase(current.element.getId()))
tree.addChild(current, tmp);
}
}*/
addChildRecursive(tree, list, tree.getRoot());
tree.printTree();
}
public static void addChildRecursive(Tree tree, List<NavLink> list, TLLNode<NavLink> current)
{
if (current == null)
return;
TLLNode<NavLink> insert;
for (NavLink item : list)
{
insert = new TLLNode<>(item);
if (insert.element.getParentId() == current.element.getId())
{
tree.addChild(current, insert.element);
list.remove(insert.element);
addChildRecursive(tree, list, current.child);
}
}
}
}
The method addChildRecursive is the one that is giving me the problems, in the output it doesn't say that there are any errors.
I don't understand what needs to be done here?
P.S. Ignore the isHidden and other attributes, the main problem is with the addChildRecursive method
First of all in java it's recommended that you check if two strings are equal with now equals() function and not the == operator.
Now for your question, it's seems that you only check the child of the current node and because there could be more than one child you don't check them all.
I suggest to use a list of child or some other sort of mechanism to save all the children directly and not thru the "sibling" pointer.
I am trying to implement a shallow copy for a Linked Stack, but I am failing the J-unit test provided by my instructor.
I have tried to implement a for loop that will cycle through the stack top to bottom and create a reference for each node to the new list on the pass through. I've added a print statement and the data references seem to match up,but my test are still failing.
public class LinkedStack<E> implements Stack<E>{
private int size = 0;
// Unlike the book, we'll use an inner class for our Node.
// Its two data members can be accessed directly by the Stack
// code, so we don't need setters and getters.
protected class Node{
E data;
Node next;
}
protected Node top; // not public, but can still be seen by other classes in the
// csci211 package.
/** Create an empty stack.
*
*/
public LinkedStack(){
top = null;
}
#Override // see interface for comments.
public void push(E e){
//TODO 75
Node temp = new Node();
temp.data = e;
temp.next = top;
top = temp;
}
#Override // see interface for comments.
public E pop(){
if (top==null) {
throw new NoSuchElementException("Cannout pop an Empty Stack.");
}
E topvar;
topvar = top.data;
top = top.next;
return topvar;
}
#Override // see interface for comments.
public E peek() {
if (top == null) {
throw new NoSuchElementException("Cannout peek an Empty Stack.");
}
//E topvar;
//topvar = top.data;
return top.data;
}
/** Retrieve the number of elements on this stack.
*
* #return an int containing the number of elements
*/
public int size() {
return this.size;
}
/** An Iterator for our LinkedStack.
*
* #author rhodes
*
*/
class LinkedStackIterator implements Iterator<E> {
LinkedStack<E>.Node next; // the book calls this "current"
public LinkedStackIterator(LinkedStack<E> s){
next = s.top;
}
#Override
public boolean hasNext() {
return top != null;
//TODO 100
//return false;
}
#Override
public E next() {
if (!hasNext()) throw new NoSuchElementException();
E data = top.data;
top = top.next;
return data;
//TODO 100
//return null;
}
}
#Override
public void add(E element) {
push(element);
}
#Override
public void clear() {
this.top = null;
this.size = 0;
}
#Override
public List<E> shallowCopy() {
LinkedStack<E> newstack = new LinkedStack<E>();
ArrayList<E> Alist = new ArrayList<E>();
//Iterate through while we haven't hit the end of the stack
Node newtest = top;
while (newtest != null) {
Alist.add(newtest.data);
newtest = newtest.next;
//TODO 85
}
for(int i = Alist.size()-1;i>=0;i--) {
newstack.push(Alist.get(i));
}
return newstack;
}
#Override
public Iterator<E> iterator() {
return new LinkedStackIterator(this);
}
}
This is the Junit tests that I am failing
#Test
#SuppressWarnings("deprecation") // for Date.setHours(), Date.getHours()
public void shallowCopy1() {
// let's use Date, since it's mutable.
LinkedStack<Date> s = new LinkedStack<Date>();
Date d = new Date();
d.setHours(17);
s.push(d);
LinkedStack<Date> s2 =(LinkedStack<Date>) s.shallowCopy();
Date d2=s2.pop();
// The shallow copy should contain references to the same objects
// as the original.
assertTrue(d == d2);
// So, we can change the Date in the original list using the Date that
// came from the shallow copy.
d2.setHours(14);
assertTrue(d.getHours() == 14);
// I don't usually put two asserts in one test, but this seems like
// an instructive example.
}
#Test(expected=NoSuchElementException.class)
public void shallowCopy2() {
LinkedStack<Integer> s1 = new LinkedStack<Integer>();
for(int i=0; i<10; i++) {
s1.push(i);
}
LinkedStack<Integer> s2 =(LinkedStack<Integer>) s1.shallowCopy();
s2.push(10); // supposed to only affect s2
s2.push(11); // supposed to only affect s2
for(int i=0; i<10; i++) {
s1.pop();
}
int last = s1.pop(); // should throw
}
#Test
public void shallowCopy3() {
LinkedStack<Integer> q1 = new LinkedStack<Integer>();
for(int i=0; i<10; i++) {
q1.push(i);
}
LinkedStack<Integer> q2 =(LinkedStack<Integer>) q1.shallowCopy();
//Let's check that the order of elements is correct in the copy.
for(int i=0; i<10; i++) {
int v1=q1.pop();
int v2=q2.pop();
assertEquals(v1, v2);
}
}
If anyone could point me in the right direction I would appreciate it. This is a Homework Problem.
Shallow copies duplicate as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.
Deep copies duplicate everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.
protected class Node{
E data;
Node next;
Node(Node node){
this.next = node.next;
this.data = node.data;
}
}
#Override
public List<E> shallowCopy() {
// LinkedStack<E> newStack = new LinkedStack<E>();
//Iterate through while we haven't hit the end of the stack
Node s = new Node(top);
while (top.next != null) {
s.next = new Node(top.next);
top = top.next;
s = s.next;
}
System.out.println("FINSHED!");
return (List<E>) s;
}
#Override
public List<E> shallowCopyWithoutUpdatingNodeClass() {
// LinkedStack<E> newStack = new LinkedStack<E>();
//Iterate through while we haven't hit the end of the stack
Node s = new Node(top);
while (top.next != null) {
s.next = new Node();
s.next.next = top.next;
s.next.data = top.data;
top = top.next;
s = s.next;
}
System.out.println("FINSHED!");
return (List<E>) s;
}
Answer Inspired by :- What is the difference between a deep copy and a shallow copy?
The original problem was the node data was just being overwritten not creating a new node. Then the stack was backwards. Finally I implement and array to reverse the stack.
#Override
public List<E> shallowCopy() {
LinkedStack<E> newstack = new LinkedStack<E>();
ArrayList<E> Alist = new ArrayList<E>();
//Iterate through while we haven't hit the end of the stack
Node newtest = top;
while (newtest != null) {
Alist.add(newtest.data);
newtest = newtest.next;
//TODO 85
}
for(int i = Alist.size()-1;i>=0;i--) {
newstack.push(Alist.get(i));
}
//System.out.println("FINSHED!");
return newstack;
}
public class Node {
private final int vertex;
private final HashSet<Node> nodes;
public Node(int index) {
this.index = index;
this.nodes = new HashSet<Node>();
}
protected void addOutgoingEdge(Node a) {
nodes.add(a);
}
public class DirectedGraph {
private Map<Integer, Node> vertices;
public DirectedGraph(String str) {
this.vertices = new HashMap<Integer, Node>();
str = str.replaceAll("[a\\s\\[]", "");
String[] edges = str.split("]");
for (String edge : edges) {
String[] points = edge.split(",");
int[] integerPoint = new int[2];
integerPoint[1] = Integer.parseInt(points[1]);
Node incoming = new Node(integerPoint[0]);
Node outgoing = new Node(integerPoint[1]);
// Need to construct the map and add edges here
}
}` enter code here`
protected void addEdge(Node origin, Node destination) {
origin.addOutgoingEdge(destination);
}
I am having a bit of some trouble getting the ball rolling on my Directed Graph
I have two classes: A Node class and a DirectedGraph class. The DirectedGraph class will pass in a String to construct a graph. I can't seem to initialize the GraphNode and the respective edges in my DirectedGraph class, however. I know I will be using a Map to get unique keys but the values (outgoing edges) is screwing me up. I know I am very close, I just keep slipping up.
The sample output would be like 1-----> 2 4 -----> 3 5 ------> 4
Where the left column is the vertex and the right column is an outgoing edge. I would appreciate any tips. Here are my classes:
Hi I've coded a solution for you I refactored a little your code, and I focused on the relationship creation:
package com.stackoverflow.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* This class manages the Directed Graph creation, and all the methods related to build a Directed Graph
*
*/
public class DirectedGraph {
Map<Node, List<Node>> graph;
public DirectedGraph() {
this.graph = new HashMap<Node, List<Node>>();
}
void createRelationship(Node input, Node output) {
List<Node> outputs = graph.get(input);
//If is a new node create their output list, (all the nodes to which it has relationship)
if (outputs == null)
outputs = new ArrayList<Node>();
//Check that the node is not in the list, to avoid duplication
if (!outputs.contains(output)){
outputs.add(output);
graph.put(input,outputs);
}
}
void printGraph(){
Iterator it = this.graph.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
List<Node> outputs = (List<Node>) pair.getValue();
for(Node node : outputs){
System.out.print(pair.getKey().toString() + "-->" + node + " ");
}
it.remove(); // avoids a ConcurrentModificationException
}
}
}
------------------
package com.stackoverflow.graph;
public class Node {
//This is the only field you need for your implementation
private Integer value;
public Node(int value){
this.value = value;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
#Override
public String toString() {
return value.toString();
}
}
----------------------
package com.stackoverflow.graph;
public class App {
public static void main(String[] args) {
DirectedGraph graph = new DirectedGraph();
//This is the final result, with your parse you must prepare this code to run in this way:
Node n1 = new Node(1);//Instead of the hardcoded values 1,2,3,4,5 take the parsed ones
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(4);
Node n5 = new Node(5);
//put this code into a loop to create each edge
graph.createRelationship(n1, n2);
graph.createRelationship(n3, n4);
graph.createRelationship(n3, n5);
//Duplicate relationship but not added
graph.createRelationship(n3, n5);
graph.printGraph();
}
}
Output:
1-->2 3-->4 3-->5
Right now I am trying to create a circular list, where when I use hasNext() from an Iterator it should always return true. However right now it is returning that it is not a circular list, and I am also having problems printing out the values (in this example Strings) of the ArrayList. Here is the CircularList class I created, which has a inner Node class for the objects that are put into the list:
public class CircularList<E> implements Iterable{
private Node<E> first = null;
private Node<E> last = null;
private Node<E> temp;
private int size = 0;
//inner node class
private static class Node<E>{ //In this case I am using String nodes
private E data; //matching the example in the book, this is the data of the node
private Node<E> next = null; //next value
//Node constructors, also since in this case this is a circular linked list there should be no null values for previous and next
private Node(E data){
this.data = data;
}
}
//end of inner node class
public void addValue(E item){
Node<E> n = new Node<E>(item);
if(emptyList() == true){ //if the list is empty
//only one value in the list
first = n;
last = n;
}
else{ //if the list has at least one value already
//store the old first value
temp = first;
//the new first is the input value
first = n;
//next value after first is the old first value
first.next = temp;
//if after this there will be only two values in the list once it is done
if(size == 1){
last = temp;
}
//if the list is greater than one than the last value does not change, since any other values will be put before last in this case, and not replace it
//creating the circular part of the list
last.next = first;
}
size++;
}
public boolean emptyList(){
boolean result = false;
if(first == null && last == null){ //if there is no values at all
result = true;
}
return result;
}
#Override
public Iterator<E> iterator() {
// TODO Auto-generated method stub
return new CircularIterator<E>(); //each time this method is called it will be creating a new instance of my Iterator
}
}
Here is the Iterator class I am making:
public class CircularIterator<E> implements Iterator<E> {
#Override
public boolean hasNext() {
return false;
}
#Override
public E next() {
// TODO Auto-generated method stub
return null;
}
#Override
public void remove() {
// TODO Auto-generated method stub
}
}
and finally the Test class:
public class Test {
static CircularList<String> c = new CircularList<String>(); //in this case it is a string list
static Iterator it = c.iterator();
public static void main(String[]args){
c.addValue("Bob");
c.addValue("Joe");
c.addValue("Jaina");
c.addValue("Hannah");
c.addValue("Kelly");
Iterate();
for(String val : c){
System.out.println(val);
}
}
private static boolean Iterate(){
boolean result = false;
if(!it.hasNext()){
System.out.println("Not a circular list!");
}
else{
result = true;
}
return result;
}
}
Again I am trying to get it to always return true, I think the problem lies with my hasNext() method, but I am not completely sure.
The main problem with your approach is you are using static inner classes - this is not necessary. Making the outer class generic is sufficient. The generic parameter is then inherited by the inner classes and all sorts of issues disappear.
Implementing an Iterator properly is subtle.
public static class CircularList<E> implements Iterable<E> {
private Node first = null;
private Node last = null;
private int size = 0;
private class Node {
private E data;
private Node next = null;
private Node(E data) {
this.data = data;
}
}
public void addValue(E item) {
Node n = new Node(item);
if (emptyList()) {
//only one value in the list
first = n;
last = n;
} else { //if the list has at least one value already
//store the old first value
Node temp = first;
//the new first is the input value
first = n;
//next value after first is the old first value
first.next = temp;
//if after this there will be only two values in the list once it is done
if (size == 1) {
last = temp;
}
//if the list is greater than one than the last value does not change, since any other values will be put before last in this case, and not replace it
//creating the circular part of the list
last.next = first;
}
size++;
}
public boolean emptyList() {
boolean result = false;
if (first == null && last == null) { //if there is no values at all
result = true;
}
return result;
}
#Override
public Iterator<E> iterator() {
return new CircularIterator(); //each time this method is called it will be creating a new instance of my Iterator
}
private class CircularIterator implements Iterator<E> {
// Start at first.
Node next = first;
public CircularIterator() {
}
#Override
public boolean hasNext() {
// Stop when back to first.
return next != null;
}
#Override
public E next() {
if (hasNext()) {
E n = next.data;
next = next.next;
if (next == first) {
// We're done.
next = null;
}
return n;
} else {
throw new NoSuchElementException("next called after end of iteration.");
}
}
}
}
public void test() {
CircularList<String> c = new CircularList<>();
c.addValue("A");
c.addValue("B");
c.addValue("C");
c.addValue("D");
for (String s : c) {
System.out.println(s);
}
}
Your main code was essentially correct - all I did was remove the unnecessary generics parameters from the inner classes.
Note that the way you add node to the list means that the items come out backwards. You could adjust that in your addValue method quite easily.
You can simply use following for circular iteration. This Circular list behave as same as other java.util.Lists. But it's iteration is modified. You don't need to care about it's performance tuning additionally. Because it's super class (LinkedList) is already well tested and enough stronger to use.
`public class CircularList extends LinkedList {
#Override
public Iterator<E> iterator() {
return createIterator();
}
//create new iterator for circular process
private Iterator<E> createIterator() {
return new Iterator<E>() {
private int index = 0;
#Override
public boolean hasNext() {
//no elements when list is empty
return isEmpty();
}
#Override
public E next() {
E node = get(index);
//rotate index
index++;
if (index == size()) {
index = 0;
}
return node;
}
};
}
}`
I am writing a Graph class,
I keep a HashMap in which ids of nodes (int values) are mapped to the associated nodes, and I'm using adjacency list approach to keep edges starting from a node (keeping them in form of a HashSet)
Note that : This graph is directed and unweighted,
I want to implement a method which returns an iterator over objects of class Edge :
When getting next on this iterator , one will get an object of class Edge which is created right when it's being traversed, and if there's no more neighbors for a node, it goes to the next node (order is not important) and if there's no more starting nodes (all are traversed), it finishes.
Any idea on how to implement this iterator on the edges without previously keeping the edges in Edge class objects ?
class Graph{
HashMap<Integer , GraphNode> nodes;
public Graph(){
nodes = new HashMap<Integer ,GraphNode>();
}
public boolean addEdge(GraphNode n1 , GraphNode n2){
if (!nodes.containsKey(n1) || !nodes.containsKey(n2))
return false;
return n1.addNeighbor(n2);
}
public boolean addNode(int id){
if (nodes.containsKey(id))
return false;
nodes.put(id , new GraphNode(id));
return true;
}
public boolean removeNode(GraphNode n1){
if (!nodes.containsKey(n1.content))
return false;
for (GraphNode m : n1.neighbors)
m.removeNeighbor(n1);
nodes.remove(n1);
return false;
}
public boolean removeEdge(GraphNode n1 , GraphNode n2){
if (!nodes.containsKey(n1) || !nodes.containsKey(n2))
return false;
return n1.removeNeighbor(n2);
}
public Iterator<GraphNode> NodeIterator(){
return nodes.values().iterator();
}
public Iterator<Edge> EdgeIterator(){
Iterator<GraphNode> itr = this.NodeIterator();
while (itr.hasNext){
GraphNode n = itr.next();
//......
}
}
}
class GraphNode{
HashSet<GraphNode> neighbors;
int content;
public GraphNode(int content){
this.content = content;
neighbors = new HashSet<GraphNode>();
}
boolean addNeighbor(GraphNode n){
if (neighbors.contains(n))
return false;
neighbors.add(n);
return true;
}
boolean removeNeighbor(GraphNode n){
if (!neighbors.contains(n))
return false;
neighbors.remove(n);
return true;
}
}
class Edge{
Node start , end;
public Edge(Node start , Node end){
this.start = start;
this.end = end;
}
}
I think something like this might work :
public Iterator<Edge> EdgeIterator(){
Iterator <Edge> edgeIter = new Iterator<Edge>() {
private Iterator<GraphNode> itr = this.NodeIterator();
private GraphNode currentNode;
... // additional private members as required
public void remove()
{
// you don't have to implement this method if you don't need to support
// this operation
}
public Edge next()
{
if (!hasNext())
throw new NoSuchElementException ();
return new Edge (x , y); // where you find x & y based on the current state
// of the iterator (kept in the private members of
// this instance)
}
public boolean hasNext()
{
return ?; // you return a boolean value based on the current state
// of the iterator (kept in the private members of
// this instance)
}
};
return edgeIter;
}
The EdgeIterator method creates an Iterator<Edge> and defines the methods of the Iterator interface (I left the implementation of these methods to you). The Iterator instance contains an instance of Iterator<GraphNode>, which it uses to iterate over the nodes.
You should add to the iterator some additional private members that keep track of the current node (the last node returned by the node iterator) and the current edge you are iterating on. Whenever you finish iterating over the edges of a node, you get the next node using itr.next() (after checking there is a next node available). next() of the edge iterator can construct the next Edge based on those private members.
As Eran said , I completed the code of the iterator methods ,
Do you think this one works ?
public Iterator<Edge> EdgeIterator(){
Iterator<Edge> edgeIter = new Iterator<Edge>() {
private Iterator<GraphNode> node_itr = NodeIterator();
private Iterator<GraphNode> neighbor_itr;
private GraphNode current_node;
private GraphNode current_neighbor;
public void remove()
{
if (current_node == null || current_neighbor == null)
return;
current_node.removeNeighbor(current_neighbor);
}
public Edge next()
{
if (neighbor_itr == null || !neighbor_itr.hasNext())
if (node_itr.hasNext()){
current_node = node_itr.next();
neighbor_itr = current_node.neighbors.iterator();
}else
return null;
current_neighbor = neighbor_itr.next();
return new Edge(current_node , current_neighbor);
}
public boolean hasNext()
{
if (neighbor_itr == null || !neighbor_itr.hasNext())
if (node_itr.hasNext())
return node_itr.next().neighbors.iterator().hasNext();
else
return false;
return true;
}
};
return edgeIter;
}
Update : The edited/working version :
public Iterator<Edge> EdgeIterator(){
Iterator<Edge> edgeIter = new Iterator<Edge>() {
private Iterator<GraphNode> node_itr = NodeIterator();
private Iterator<GraphNode> neighbor_itr;
private GraphNode current_node;
private GraphNode current_neighbor;
public void remove()
{
if (current_node == null || current_neighbor == null)
return;
current_node.removeNeighbor(current_neighbor);
}
private void moveNext(){
if (neighbor_itr == null || !neighbor_itr.hasNext()){
while (node_itr.hasNext()){
current_node = node_itr.next();
neighbor_itr = current_node.neighbors.iterator();
if (neighbor_itr.hasNext()){
break;
}
}
}
}
public Edge next()
{
moveNext();
current_neighbor = neighbor_itr.next();
return new Edge(current_node , current_neighbor);
}
public boolean hasNext()
{
moveNext();
return neighbor_itr.hasNext();
}
};
return edgeIter;
}