Before all, here is a Minimal Working Example of my code on GitHub:
https://github.com/rmwesley/DancingLinks_MWE
I've been trying to implement the Dancing Links' algorithm by D. Knuth to solve the Exact Cover problem.
The code works. Problem is, I want to implement an Iterator.
In fact, the Iterator works for Node.java.
But not for Column.java, as I will further detail.
I've tried completely refactoring the code and doing some crazy modifications, but to no avail.
I left some of my best trials as commented lines of code.
These were the least garbagey ones.
My current design is as follows:
Given a problem matrix, I aimed at constructing the main data structure with 4-way nodes.
So first I implemented Node.java, a 4-way circularly linked data structure.
Then I extend Node.java in Column.java, which is the "backbone" of the structure.
Column elements then make up the main row.
Rows of Nodes are then linked with the rest of the structure with .addRow().
That is, new rows come below the last added row and above the column. Remember, circular.
See the schematics in D. Knuth's paper: https://arxiv.org/abs/cs/0011047.
With this, the full structure can be initialized from a given problem matrix.
"this" in Column serves as the head itself, so no elements are added above or below it.
Here is my source code:
Node.java
public class Node implements Iterable<Node> {
private Node upNode;
private Node downNode;
private Node leftNode;
private Node rightNode;
private Column column;
public Node() {
upNode = this;
downNode = this;
leftNode = this;
rightNode = this;
column = null;
}
#Override
public String toString() {
String str = this.column.getSize() + " ";
for (Node node : this){
str += node.column.getSize() + " ";
}
return str;
}
#Override
public java.util.Iterator<Node> iterator(){
Node currNode = this;
return new NodeIter(this);
}
public Column getColumn(){
return this.column;
}
public void setColumn(Column column){
this.column = column;
}
public Node getR(){
return this.rightNode;
}
public Node getD(){
return this.downNode;
}
public Node getL(){
return this.leftNode;
}
public Node getU(){
return this.upNode;
}
void removeHoriz() {
this.rightNode.leftNode = this.leftNode;
this.leftNode.rightNode = this.rightNode;
}
void removeVert() {
this.downNode.upNode = this.upNode;
this.upNode.downNode = this.downNode;
}
void restoreVert() {
this.downNode.upNode = this;
this.upNode.downNode = this;
}
void restoreHoriz() {
this.rightNode.leftNode = this;
this.leftNode.rightNode = this;
}
//Create an horizontal link between nodes
public void linkD(Node other) {
this.downNode = other;
other.upNode = this;
}
//Create a vertical link between nodes
public void linkR(Node other) {
this.rightNode = other;
other.leftNode = this;
}
void addHoriz(Node other) {
other.rightNode = this.rightNode;
other.leftNode = this;
}
void addVert(Node other) {
other.downNode = this.downNode;
other.upNode = this;
}
}
Column.java
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
//public class Column extends Node implements Iterable<Column>{
public class Column extends Node {
private int size;
private String name;
public Column() {
super();
this.setColumn(this);
size = 0;
name = new String();
}
public Column(int length) {
this();
Column currColumn = this;
for(int i = 0; i < length; i++){
currColumn.setName("" + i);
Column nextColumn = new Column();
currColumn.linkR(nextColumn);
currColumn = nextColumn;
}
currColumn.linkR(this);
}
public void addRow(int[] vector) throws Exception {
Column currColumn = this;
Node firstNode = new Node();
Node currNode = firstNode;
Node prevNode = currNode;
for(int index=0; index < vector.length; index++){
currColumn = currColumn.getR();
if(vector[index] == 0) continue;
currColumn.increment();
currColumn.getU().linkD(currNode);
currNode.linkD(currColumn);
currNode.setColumn(currColumn);
prevNode = currNode;
currNode = new Node();
prevNode.linkR(currNode);
}
currColumn = currColumn.getR();
prevNode.linkR(firstNode);
if(currColumn != this){
throw new Exception("Differ in length");
}
}
public Column(int[][] matrix) throws Exception {
this(matrix[0].length);
for(int i = 0; i < matrix.length; i++){
this.addRow(matrix[i]);
}
}
#Override
public Column getR(){
return (Column) super.getR();
}
#Override
public Column getL(){
return (Column) super.getL();
}
#Override
public String toString(){
String str = "";
//for (Column currColumn : this) str += currColumn.getSize() + " ";
for (Column currColumn = this.getR();
currColumn != this;
currColumn = currColumn.getR()){
str += currColumn.getSize() + " ";
}
return str;
}
public String getName(){
return this.name;
}
public int getSize(){
return this.size;
}
public void setSize(int size){
this.size = size;
}
public void setName(String name){
this.name = name;
}
public void increment(){
this.size++;
}
public void decrement(){
this.size--;
}
/*
#Override
public Iterator<Column> iterator(){
return new Iterator<Column>(){
private Column currNode = Column.this;
#Override
public boolean hasNext(){
return currNode.getR() != Column.this;
}
#Override
public Column next(){
if (!hasNext()) throw new NoSuchElementException();
currNode = currNode.getR();
return currNode;
}
};
}
*/
}
NodeIter.java
public class NodeIter implements java.util.Iterator<Node>{
private Node head;
private Node current;
public NodeIter(Node node){
this.head = this.current = node;
}
#Override
public boolean hasNext(){
return current.getR() != head;
}
#Override
public Node next(){
if (!hasNext()) throw new java.util.NoSuchElementException();
current = current.getR();
return current;
}
}
Commented lines give these errors when uncommented:
src/Column.java:5: error: Iterable cannot be inherited with different arguments: <Column> and <Node>
public class Column extends Node implements Iterable<Column>{
^
src/Column.java:111: error: iterator() in Column cannot implement iterator() in Iterable
public Iterator<Column> iterator(){
^
return type Iterator<Column> is not compatible with Iterator<Node>
where T is a type-variable:
T extends Object declared in interface Iterable
src/Column.java:76: error: incompatible types: Node cannot be converted to Column
for (Column currColumn : this) str += currColumn.getSize() + " ";
How do I make Column.java iterable?
I've been coding in Java recently, but without carefully considering design patterns.
So I fully believe I am suffering the consequences of bad code design.
Should I make some abstract class or make use of some Generic Type?
Like Node and Column, just so I can implement Iterable.
Am I wrong?
Does anyone have any pointers?
Tried using generics and overriding .iterator() method with different return types in Column.java.
Even tried using completely different class structures.
The Node class has an implementation of the Iterable interface in the form of one method:
#Override
public java.util.Iterator<Node> iterator(){
Node currNode = this;
return new NodeIter(this);
}
(BTW the first line of this method is not doing anything useful)
You are trying to make Node's subclass Column implement Iterable, meaning you want to add an overriding method like this:
#Override
public Iterator<Column> iterator()
Such an override which only differs in return type is not allowed in Java, hence the compilation error.
The fundamental problem is that, since Node is an Iterable, all its subclasses will also be an Iterable due to inheritance.
I guess you would like to write code like this:
for(Node n : node) {
for(Column c : n.getColumn()) {
c.increment();
}
}
Currently I think you could do this:
for(Node n : node) {
for(Node c : n.getColumn()) {
((Column) c).increment();
}
}
Where you are casting the iterand to Column in order to access Column methods.
I do think the design is weird when I read this for instance:
public Column() {
super();
this.setColumn(this);
eh? So a Column is a Node which has a column field? Seems like the design is conflicted about whether a Column is-a Node, or a Node has-a Column... I feel like your iterable problem will magically disappear once you figure that out.
EDIT: I don't fully grasp the algorithm and data structure yet (although I read a bit about it). From what I've understood I think you should create something like the following structure:
class Matrix {
Column[] columns;
Matrix(int[][] input) {
// init Columns
}
}
class Column {
String name;
int size;
Node firstNode;
}
class Node {
Node up;
Node down;
Node left;
Node right;
}
And avoid sub classing, it's usually not needed. Better to work with interfaces and collaborators.
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.
I am trying to copy a binary tree using the pre order traversal but I am stuck.
As I am not putting any of the values into a new tree they are obviously not copying correctly...
public class Node{
int key;
String name;
Node leftChild;
Node rightChild;
Node(int key, String name){
this.key = key;
this.name = name;
}
public class BinaryTree{
public Node root;
public void copyTree(Node focusNode){
if(focusNode != null){
Node copyNode = new Node(focusNode.key, focusNode.name);
//System.out.println(copyNode);
copyTree(focusNode.leftChild);
copyTree(focusNode.rightChild);
}
}
}
Here's one solution. I added a toString() method to the Node class for presentation purposes.
class Node {
int key;
String name;
Node leftChild;
Node rightChild;
Node(int key, String name) {
this.key = key;
this.name = name;
}
public String toString() {
return "[" + key + "," + name + "]";
}
}
The BinaryTree was slightly modified as well:
class BinaryTree {
public Node root;
public BinaryTree copyTree(Node focusNode) {
BinaryTree bt = new BinaryTree();
bt.root = preOrderCopy(focusNode);
return bt;
}
public static void preOrderPrint(BinaryTree t) {
preOrderPrint(t.root);
}
public static void preOrderPrint(Node n) {
if (n == null) {
// base case
return;
}
System.out.println(n);
preOrderPrint(n.leftChild);
preOrderPrint(n.rightChild);
}
private Node preOrderCopy(Node focusNode) {
if (focusNode == null) {
// base case
return null;
}
Node copy = new Node(focusNode.key, focusNode.name);
copy.leftChild = preOrderCopy(focusNode.leftChild);
copy.rightChild = preOrderCopy(focusNode.rightChild);
return copy;
}
}
To test the code, I created a BinaryTree based on the one shown on the Wikipedia page for Tree Traversal. Here's a picture of the tree used in this example:
The proper Pre-order traversal for this example is : F, B, A, D, C, E, G, I, H. You can use the following code to test this implementation:
public class NodeTest {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
Node a = new Node(1, "A");
Node b = new Node(2, "B");
Node c = new Node(3, "C");
Node d = new Node(4, "D");
Node e = new Node(5, "E");
Node f = new Node(6, "F");
Node g = new Node(7, "G");
Node h = new Node(8, "H");
Node i = new Node(9, "I");
f.leftChild = b;
b.leftChild = a;
b.rightChild = d;
d.leftChild = c;
d.rightChild = e;
f.rightChild = g;
g.rightChild = i;
i.leftChild = h;
bt.root = f;
System.out.println("Print full tree:");
BinaryTree.preOrderPrint(bt.copyTree(f));
System.out.println("Only print f's left sub-tree:");
BinaryTree.preOrderPrint(bt.copyTree(f.leftChild));
}
}
Running the above code produces the following output:
Print full tree:
[6,F]
[2,B]
[1,A]
[4,D]
[3,C]
[5,E]
[7,G]
[9,I]
[8,H]
Only print f's left sub-tree:
[2,B]
[1,A]
[4,D]
[3,C]
[5,E]
To copy from tree a to tree b. you can use two static method like me. My idea comes from adding Element method and removing Element method. they are similar.
public static Node copyRec(Node a, Node b)//copy from b to a
{
if(b!=null)
{
a=new Node(b.data);
a.leftChild=copyRec(a.leftChild,b.leftChild);
a.rightChild=copyRec(a.rightChild,b.rightChild);
return a;
}
return null;
}
public static void copy(BST a, BST b)
{
a.root=copyRec(a.root,b.root);
}
I've a university project about creating two classes, Tree class and Node class, to implement a k-ary tree using Java.
In the class Tree, there should be a constructor which recives as input an int that indicates the tree arity.
I've worked before with general trees and this was my result:
Class tree: *
Class node: *
I absolutely don't know where and how to start to build this project (as I don't know how to manage the arity, maybe with ArrayList?).
Any advice and suggestions will be greatly appreciated :)
Thanks in advance.
Here are the new versions of the classes, with the methods that you needed.
Node:
import java.util.ArrayList;
import java.util.List;
public class Node {
public Node parent; // The parent of the current node
public List<Node> children; // The children of the current node
public Object info;
public static int maxNrOfChildren; // Equal to the k-arity;
public Node (Object info)
{
this.info=info;
children = new ArrayList<Node>(maxNrOfChildren);
}
public void addChild(Node childNode, int position)
// You must take care so that future insertions don't override a child on i-th position
{
if(position>=maxNrOfChildren-1)
{
// Throw some error
}
else
{
System.out.println("this.children="+this.children);
if(this.children.get(position)!=null)
{
// There is alerady a child node on this position; throw some error;
}
else
{
childNode.parent=this;
this.children.set(position, childNode);
}
}
}
}
Tree:
import java.util.ArrayList;
import java.util.List;
public class Tree {
public Node root;
public Tree(int kArity)
{
Node.maxNrOfChildren=kArity;
}
public void addRoot(Object info)
{
root=new Node(info);
root.parent=null;
root.children=new ArrayList<Node>(Node.maxNrOfChildren);
}
public void addNewNodeVasithChildOfNodeU(Node u, Object info, int i)
{
Node child=new Node(info);
u.addChild(child, i);
}
// I've made the above two methods of type void, not Node, because
// I see no reason in returning anything; however, you can override by calling
//'return root;' or 'return child;'
public int numberOfNodesInTree(Node rootNode){
int count=0;
count++;
if(rootNode.children.size()!=0) {
for(Node ch : rootNode.children)
count=count+numberOfNodesInTree(ch);
}
return count;
}
public int numberOfNodesInTree()
{
return numberOfNodesInTree(this.root);
}
public void changeRoot(Node newRoot, int i)
{
Node oldRoot=this.root;
newRoot.parent=null;
newRoot.addChild(oldRoot, i);
oldRoot.parent=newRoot;
this.root=newRoot;
}
public static void main(String args[])
{
Tree tree=new Tree(3);
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
tree.addRoot("root");
tree.root.addChild(a,0);
a.addChild(b,0);
tree.root.addChild(c,1);
System.out.println(tree.numberOfNodesInTree(tree.root));
}
}
The logic is correct, but I am getting some Java-related error when I run the main method and I haven't yet figured out what the problem is.
this can be a starting point:
Node Class
import java.util.ArrayList;
import java.util.List;
public class Node {
public Node parent;//the parent of the current node
public List<Node> children = new ArrayList<Node>();//the children of the current node
public String name;//or any other property that the node should contain, like 'info'
public static int maxNrOfChildren;//equal to the k-arity;
public Node (String nodeName)
{
name=nodeName;
}
public void addChild(Node childNode)
{
if(this.children.size()>=maxNrOfChildren)
{
//do nothing (just don't add another node), or throw an error
}
else
{
childNode.parent=this;
this.children.add(childNode);
}
}
}
Tree Class
import java.util.ArrayList;
import java.util.List;
public class Tree {
public Node root = new Node("root");
public Tree(int kArity)
{
Node.maxNrOfChildren=kArity;
root.parent=null;
}
public void traverseTree(Node rootNode)//depth first
{
System.out.println(rootNode.name);
if(rootNode.children.size()!=0)
for(Node ch : rootNode.children)
traverseTree(ch);
}
public static void main(String args[])
{
Tree tree=new Tree(3);
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
tree.root.addChild(a);
a.addChild(b);
tree.root.addChild(c);
tree.traverseTree(tree.root);
}
}
Please give further details about your project specifications, otherwise i can't figure out which kind of functionality you need within these classes
The idea behind creating a k-array, is that this is not a conventional structure like a list or a set, the node is like an element in a linked list, it point to the n other child node and can also point to the parent, whant determine what should be the child or the parent in that sctructure is an entire different question. As for the list of child in the node you can use any structure you whant ArrayList most likely will be a good fit. The choice of a structure depend on many factors like size, how often it will be accessed does it need to be sorted etc.
Have a look at this. Hope it helps.
import java.util.ArrayList;
public class Nary
{
public static Node root;
public static int insert(Node rootNode, int parentId, ArrayList<Node> nodeToAdd)
{
if(rootNode == null)
return 0;
if(rootNode.children == null)
rootNode.children = new ArrayList<Node>();
if(rootNode.id == parentId)
{
for(int i =0; i < nodeToAdd.size(); i++)
{
Node node = nodeToAdd.get(i);
node.parent = rootNode;
rootNode.children.add(node);
}
return 1;
}
else
{
for(int i = 0; i < rootNode.children.size(); i++)
{
int resultFlag = insert(rootNode.children.get(i), parentId, nodeToAdd);
if(resultFlag == 1)
{
return 1;
}
}
}
return -1;
}
public static void traverse(Node root)
{
if(root == null)
{
return;
}
System.out.println(root.data + " " + root.id );
for(Node child : root.children)
{
traverse(child);
}
}
public static void main(String[] args) {
// Insertion
root = new Node(0, "root");
int parentId = root.id;
Node Bread = new Node(1, "Bread");
Node Milk = new Node(2, "Milk");
Node Meat = new Node(3, "Meat");
Node Eggs = new Node(4, "Eggs");
ArrayList<Node> nodeList = new ArrayList<Node>();
nodeList.add(Bread);
nodeList.add(Milk);
nodeList.add(Meat);
nodeList.add(Eggs);
insert(root, parentId, nodeList);
// Add children for Bread
parentId = Bread.id;
Node Bread0 = new Node(11, "Whole-Wheat");
Node Bread1 = new Node(12, "Whole-Grain");
Node Bread2 = new Node(13, "Italian");
ArrayList<Node> nodeList1 = new ArrayList<Node>();
nodeList1.add(Bread0);
nodeList1.add(Bread1);
nodeList1.add(Bread2);
insert(root, parentId, nodeList1);
Add children for Milk
parentId = Milk.id;
Node Milk0 = new Node(21, "Whole");
Node Milk1 = new Node(22, "skim");
Node Milk2 = new Node(23, "Almond");
ArrayList<Node> nodeList2 = new ArrayList<Node>();
nodeList2.add(Milk0);
nodeList2.add(Milk1);
nodeList2.add(Milk2);
insert(root, parentId, nodeList2);
traverse(root);
}
}
class Node{
int id;
String data;
Node parent;
ArrayList<Node> children;
public Node(int id, String data)
{
this.id = id;
this.data = data;
}
}