I need to loop in a tree to get all possible paths, the problem in my code that i get just the first path!
example:
In the figure, there are 2 paths t handle: 1-2-3-4-5-6 and 1-2-3-7-8 , but i couldn't get both, i have just retrieved 1-2-3-4-5-6 !
my code:
In main:
for (String key : synset.keySet()) { // looping in a hash of Concept and it's ID
System.out.println("\nConcept: " + key + " " + synset.get(key));
List<Concept> ancts = myOntology.getConceptAncestors(myOntology.getConceptFromConceptID(synset.get(key))); // this function retreives the root of any node.
for (int i = 0; i < ancts.size(); i++) {
System.out.print(ancts.get(i).getConceptId() + " # ");
System.out.print(getChilds(ancts.get(i).getConceptId()) + " -> "); // here, the recursive function is needed to navigate into childs..
}
System.out.println("");
}
Rec. function:
public static String getChilds(String conId)
{
List<Concept> childs = myOntology.getDirectChildren(myOntology.getConceptFromConceptID(conId)); // get all childs of a node
if(childs.size() > 0)
{
for (int i = 0; i < childs.size(); i++) {
System.out.print( childs.size() + " ~ " + childs.get(i).getConceptId() + " -> ");
return getChilds(childs.get(i).getConceptId());
}
}
else
return "NULL";
return "final";
}
I didn't really see enough of your code to use the classes that you have defined. So I went for writing my own working solution.
In the following code, the problem is solved using recursion:
public class TreeNode {
private String id;
private TreeNode parent;
private List<TreeNode> children;
public TreeNode(String id) {
this.id = id;
this.children = new LinkedList<>();
}
public void addChild(TreeNode child) {
this.children.add(child);
child.setParent(this);
}
public List<TreeNode> getChildren() {
return Collections.unmodifiableList(this.children);
}
private void setParent(TreeNode parent) {
this.parent = parent;
}
public TreeNode getParent() {
return this.parent;
}
public String getId() {
return this.id;
}
}
public class TreePaths {
private static List<List<TreeNode>> getPaths0(TreeNode pos) {
List<List<TreeNode>> retLists = new ArrayList<>();
if(pos.getChildren().size() == 0) {
List<TreeNode> leafList = new LinkedList<>();
leafList.add(pos);
retLists.add(leafList);
} else {
for (TreeNode node : pos.getChildren()) {
List<List<TreeNode>> nodeLists = getPaths0(node);
for (List<TreeNode> nodeList : nodeLists) {
nodeList.add(0, pos);
retLists.add(nodeList);
}
}
}
return retLists;
}
public static List<List<TreeNode>> getPaths(TreeNode head) {
if(head == null) {
return new ArrayList<>();
} else {
return getPaths0(head);
}
}
}
To use the above code, a tree must be constructed using the TreeNode class. Start off by creating a head TreeNode, then add child nodes to it as required. The head is then submitted to the TreePaths getPaths static function.
After getPaths checks for null, the internal getPaths0 function will be called. Here we follow a depth first approach by trying to get to all leaf nodes as soon as possible. Once a leaf node is found, a List only containing this leaf node will be created and returned inside the list collection. The parent of this leaf node will then be added to the beginning of the list, which will again be put into a list collection. This will happen for all children of the parent.
In the end, all possible paths will end up in a single structure. This function can be tested as follows:
public class TreePathsTest {
TreeNode[] nodes = new TreeNode[10];
#Before
public void init() {
int count = 0;
for(TreeNode child : nodes) {
nodes[count] = new TreeNode(String.valueOf(count));
count++;
}
}
/*
* 0 - 1 - 3
* - 4
* - 2 - 5
* - 6
* - 7 - 8
* - 9
*/
private void constructBasicTree() {
nodes[0].addChild(nodes[1]);
nodes[0].addChild(nodes[2]);
nodes[1].addChild(nodes[3]);
nodes[1].addChild(nodes[4]);
nodes[2].addChild(nodes[5]);
nodes[2].addChild(nodes[6]);
nodes[2].addChild(nodes[7]);
nodes[7].addChild(nodes[8]);
nodes[7].addChild(nodes[9]);
}
#Test
public void testPaths() {
constructBasicTree();
List<List<TreeNode>> lists = TreePaths.getPaths(nodes[0]);
for(List<TreeNode> list : lists) {
for(int count = 0; count < list.size(); count++) {
System.out.print(list.get(count).getId());
if(count != list.size() - 1) {
System.out.print("-");
}
}
System.out.println();
}
}
}
This will print out:
0-1-3
0-1-4
0-2-5
0-2-6
0-2-7-8
0-2-7-9
Note: The above is enough for manual testing, but the test function should be modified to do proper assertions for proper automated unit testing.
maybe this code segment in getChilds() exist problem:
for (int i = 0; i < childs.size(); i++) {
System.out.print( childs.size() + " ~ " + childs.get(i).getConceptId() + " -> ");
return getChilds(childs.get(i).getConceptId());
}
the for loop cant play a role, it always return getChilds(childs.get(0).getConceptId());
maybe this is not what you want.
One simple way.
All you need is a tree traversal and little bit of custom code.
Have a list called tempPath. you can take it as an argument or a global variable.
Do a tree traversal(eg. inorder). Whenever you are at a node add this to tempPath list at the end and when you are done with this node remove the node from the end of tempPath.
whenever you encounter a leaf, you have one full path from root to leaf which is contained in tempPath. you can either print or copy this list value into another data structure.
Related
I am creating a program that inserts a character (number/letter) into a binary tree. So far, I'm able to produce an output but it's not what I expected. These are the problems I'm encountering:
The insert method is not able to print the correct height of the tree. I am not sure where I should insert my height++; statement to get the correct output.
The insert method is only able to add nodes to the right.
Expected Output: ht=3 [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]]
My Output: ht=4 [K=3 R=[K=1 R=[K=2 R=[K=5 R=[K=4]]]]
(all nodes are only added to the right 'R')
Here are my classes for reference:
Main Class
BST<Character> bst = new BST<>();
bst.insert('3');
bst.insert('1');
bst.insert('2');
bst.insert('5');
bst.insert('4');
System.out.println("ht=" + bst.height + " " + bst.toString());
BST Class - where the insert method is declared
public class BST<T> extends BT<T> {
// insert() method
public void insert(char k)
{
if (root == null) {
root = new BTNode(k);
return;
}
BTNode<T> n = root;
BTNode<T> p = null; // parent
while (n != null) {
p = n;
if (k < n.value) {
n = n.left;
} else {
n = n.right;
}
}
if (k < p.value) {
p.left = new BTNode(k);
} else {
p.right = new BTNode(k);
height++; // adds 1 to height when a new level is made
}
}
}
BTNode Class
public class BTNode<T> {
T info;
int value, level;
BTNode<T> left, right;
public BTNode(T el) {
this(el, null, null);
}
public BTNode(T el, BTNode<T> l, BTNode<T> r) {
info = el;
left = l;
right = r;
}
}
BT Class - where the toString method is declared
public class BT<T> {
BTNode<T> root = null;
int height = 0;
public BT() {
BTNode<T> node = new BTNode("");
}
// other methods
// toString()
public String toString() {
return toString(root);
}
public String toString(BTNode<T> n) {
String s = "";
if (n == null) {
return "";
}
if (n != null) {
s = "[K=" + n.info;
if (n.left != null) {
s = s + " L=" + toString(n.left) + "]";
}
if (n.right != null) {
s = s + " R=" + toString(n.right) + "]";
}
}
return s;
}
}
Hope you can help me out, thanks!
You have quite a few issues in your code. I'll list a few immediate items but you really will need to learn to use an interactive debugger and unit testing to resolve the sorts of issues you are seeing.
You refer to the value field in BTNode in your comparison but it is never set. You should really be referring to info (which is the actual data in the node).
But given info is a generic type you can't use standard comparison operators. Instead you'll need to define it as <T extends Comparable<T>> and then use n.info.compareTo(k) > 0.
The key passed into insert should also be of type T
Which means the other classes also need to ensure T extends Comparable.
Height is only incremented when nodes are added to the right which makes no sense.
Height needs to be increased only when a node is inserted further from the root than the current maximum. Something like the following:
int depth = 0;
while (n != null) {
depth++;
p = n;
...
}
depth++;
if (depth > height)
height = depth;
You should get used to making your fields private and accessing them through getters. In your case a compareValue method would likely make sense.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 10 months ago.
Improve this question
I have a Node class used to represent a tree structure. Within this class, I've defined a print method that should yield the following output:
data
--a (1024)
--b (256)
----ba (100)
------baa (500)
------bac (25)
----bc (150)
----bd (125)
----be (75)
--c (35)
----cb (30)
----ce (50)
This is how I've written my print method:
public void print(String name) {
Node node = this.find(name);
System.out.println(node.name);
if (node.childrensCount != 0) {
for (int i = 0; i < node.childrensCount; i++) {
Node children = node.childrens[i];
System.out.println("--" + children.name + " (" + children.value + ")");
if (children.childrensCount != 0) {
for (int j = 0; j < children.childrensCount; j++) {
Node grandChildren = children.childrens[j];
System.out.println("----" + grandChildren.name + " (" + grandChildren.value + ")");
if (grandChildren.childrensCount != 0) {
for (int k = 0; k < grandChildren.childrensCount; k++) {
Node greatGrandChildren = grandChildren.childrens[k];
System.out.println("------" + greatGrandChildren.name + " (" + greatGrandChildren.value + ")");
}
}
}
}
}
}
}
This is also the Node class implementation to better help you in understanding the scenario:
public class Node {
int value;
String name;
Node parent;
int childrensCount;
Node[] childrens = new Node[100];
public Node(int value, String name) {
this.value = value;
this.name = name;
this.childrensCount = 0;
}
public Node(String name) {
this.name = name;
}
public void addChildren(Node node)
{
this.childrens[childrensCount] = node;
childrensCount++;
}
public void setParent(Node parent)
{
this.parent = parent;
}
public boolean hasParent(){
return this.parent != null;
}
public int sumValue(){
int sum = 0;
sum += this.value;
for (int i = 0; i < childrensCount; i++) {
sum += childrens[i].value;
}
return sum;
}
}
I think my code is quite dirty and can be improved. I'd like to define a recursive method but I still don't understand how recursion works. Could someone help me with that?
You can do it using recursion. Rather than try to reconstruct your data in all its complexity I created a simple example using my own node class.
class MyNode {
String name;
List<MyNode> nodeList;
public MyNode(String name) {
this.name = name;
}
public MyNode setNodeList(List<MyNode> list) {
nodeList = list;
return this;
}
#Override
public String toString() {
return name;
}
public List<MyNode> getNodeList() {
return nodeList;
}
}
MyNode m = new MyNode("a");
List<MyNode> list1 =
List.of(new MyNode("aaa"), new MyNode("aab"),
new MyNode("aac"), new MyNode("aad"));
List<MyNode> list2 = List.of(new MyNode("aba"),
new MyNode("abb"), new MyNode("abc"));
List<MyNode> list3 = List.of(new MyNode("aca"),
new MyNode("acb"), new MyNode("acc"));
List<MyNode> list4 = List.of(new MyNode("ada"),
new MyNode("adb"), new MyNode("adc"));
List<MyNode> mainlist = List.of(new MyNode("aa").setNodeList(list1),
new MyNode("ab").setNodeList(list2), new MyNode("ac").setNodeList(list3), new MyNode("ad").setNodeList(list4));
m.setNodeList(mainlist);
print(m,1);
prints
--a
----aa
------aaa
------aab
------aac
------aad
----ab
------aba
------abb
------abc
----ac
------aca
------acb
------acc
----ad
------ada
------adb
------adc
this works by having the print method calling itself and adjusting the indentation level.
The current node and level are printed.
if that node's list is non-null, then the print method is called for each node in the list and the process repeated, updating the level.
upon each return, the method starts where it left off as it continues to call itself and return.
This is a common process for walking thru hie-rarchical data sets and will work with an indeterminate amount of levels.
public static void print(MyNode node, int level) {
System.out.println("-".repeat(level*2) + node);
if (node.getNodeList() != null) {
for (MyNode n : node.getNodeList()) {
print(n, level+1);
}
}
}
I recommend you read up on recursive processes. In some cases you can also return values as you traverse the hierarchy.
To define a recursive method, you first need to identify your base cases and recursive cases. In this scenario, the base case is when the node passed for the printing is null while the recursive case is when there are still children to be printed.
Since I understand that your program might be a school exercise, I'll avoid discussing what could be or could be not a better implementation of your Node class. Definitely, using a List data structure from the Collections framework would have been a better choice instead of a fixed array of 100 elements, but I think your teacher would like to keep things simple at the beginning and you most likely haven't covered the Collections framework yet since you said you're still struggling with recursion (which is totally fine, we all have to start somewhere!). So, I'll leave your class implementation exactly how it is. I will just add few methods and some tweaks.
Here, I've implemented a solution to show you how your recursive print could work. Bear in mind that I've split the print implementation in two methods only to make its invocation easier for the client. In fact, a client should not be aware nor bothered with the internal implementation details of something to make it work.
//Test class
public class Test {
public static void main(String[] args) {
Node root = new Node(1, "test1", new Node[]{
new Node(2, "test2", new Node[]{
new Node(5, "test6", new Node[]{})
}),
new Node(3, "test3", new Node[]{
new Node(6, "test6", new Node[]{}),
new Node(7, "test7", new Node[]{
new Node(8, "test8", new Node[]{})
})
}),
new Node(4, "test4", new Node[]{})
});
root.print();
}
}
class Node {
int value;
String name;
Node parent;
int childrenCount;
Node[] children = new Node[100];
public Node(int value, String name) {
this.value = value;
this.name = name;
this.childrenCount = 0;
}
//Added second constructor only to ease the test
public Node(int value, String name, Node[] children) {
this.value = value;
this.name = name;
this.children = children;
this.childrenCount = getNumChildren(children);
}
public Node(String name) {
this.name = name;
}
//Fixed possible exception when added more than 100 elements
public boolean addChildren(Node node) {
if (childrenCount == this.children.length) {
return false;
}
this.children[childrenCount++] = node;
return true;
}
public void setParent(Node parent) {
this.parent = parent;
}
public boolean hasParent() {
return this.parent != null;
}
public int sumValue() {
int sum = 0;
sum += this.value;
for (int i = 0; i < childrenCount; i++) {
sum += children[i].value;
}
return sum;
}
//small utility method only to compute the effective number of children when an array is passed within the new constructor
public static int getNumChildren(Node[] children) {
int num = 0;
while (num < children.length && children[num] != null) {
num++;
}
return num;
}
//print method invoked by the client of the class
public void print() {
printRec(this, 0);
}
//recursive print
private void printRec(Node n, int numCall) {
//identifying the base case
if (n == null) {
return;
}
//Printing as many dahses as the depth of the current child node
for (int i = 1; i <= numCall; i++) {
System.out.print("--");
}
//printing the node info
System.out.println(n.name + " (" + n.value + ")");
//recursively invoking the print method for each child
for (int i = 0; i < n.childrenCount; i++) {
printRec(n.children[i], numCall + 1);
}
}
}
Here I just wanted to add a couple of side notes:
children is already the plural form of child. You don't need to call your array childrens.
Your previous implementation of the add method could have raised an ArraIndexOutOfBoundsException, if you had added more than 100 elements. Usually, when an operation could fail, the method should return a boolean to tell the client whether the operation succeeded or not.
(java)
I have class called Node, which has following fields:
value (integer)
connectedNodes (array of Node objects, always has same size = 2)
combination (object of Combination class)
Combination class has one field called messageContext, let's just say that it's a message which needs to be shown on the screen when something happens (described later).
Also, we have one Tree object, which has only one field: root (Node object)
Now, let's say that we have one String called combinationStr = "1121". Now, we use Tree's method called addCombination:
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
finalCombination object is an object that is going to be assigned to the last Node's combination field, added to the Tree for one combinationStr. So, we use this function to create the Tree-like structure that has path: -1 (root) -> 1 -> 1 -> 2 -> 1
When we come to the last one, traversing the Tree, we should see message appear. This is the messageContext of finalCombination.
Okay so, now let's use while(true) loop that will let us input a number, which will be like a path-chooser. If we input 1, we will go to node 1 and have other options to choose.
While loop looks like this:
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
continue;
}
System.out.print("nullnode ");
}
System.out.println("");
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
}
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
System.out.println("root");
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode,x);
}
So, what are we doing here is actually printing the value of current Node, then printing values of Node's we can go to. If Node doesn't exist, we print nullnode.
The takeStep() method looks like this:
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}
It just checks if there is a node we want to go to and returns that node, if it does. If it doesn't exist, it will return us to root.
But, what's the problem with this code ?
Well, look at the whole main class:
Tree tree = new Tree(new Node(-1));
String[] combination = {"1121","11","2212"};
for(String s: combination) {
Combination tempCombination = new Combination();
tempCombination.messageContext = s + " ova poruka";
tree.addCombination(tempCombination,tree.root,s,0);
tree.traverse(tree.root);
System.out.println("END");
}
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
System.out.println(currentNode.value);
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
}
else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
break;
}
}
currentNode = tree.takeStep(currentNode,x);
}
When we enter number x, we will call takeStep and check if that node exists connected to current one. But the problem is: When we input 1, it prints everything normally, when we input 1 again, it prints everything normally, when we input 2, it prints everything normally... but when we input 1 again, it says there are 2 nullnodes, and for some reason it doesn't change to root. Can anyone help me please? Here are the full classes:
NODE:
public class Node {
int value;
Node[] connectedNodes = {null,null};
Combination combination;
public Node(int value) {
this.value = value;
this.combination = null;
}
}
TREE:
public class Tree {
Node root;
public Tree(Node root) {
this.root = root;
}
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
public void traverse(Node current) {
System.out.print(current.value+ " ");
for(Node node: current.connectedNodes) {
if(node!=null) {
traverse(node);
}
}
}
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}}
COMBINATION:
public class Combination {
String messageContext;
}
Can you please help me ? I just want to reset to root when it hasn't anywhere to go else ? Thank you in advance!
I ran your code and found out that you are storing the message context in the parent node instead of the actual node which marks the end of the combination. So I changed this piece of code in addCombination.
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if (counter == combination.length()) {
//Storing at the original node.
current.combination = finalCombination;
return;
}
int value = combination.charAt(counter) - 48;
if (current.connectedNodes[value - 1] == null) {
current.connectedNodes[value - 1] = new Node(value);
}
addCombination(finalCombination, current.connectedNodes[value - 1], combination, counter + 1);
}
And changed following in the main code.
while (true) {
System.out.println(currentNode.value);
//Moved it up now as the node it self has the message context.
if (currentNode.combination != null) {
System.out.println(currentNode.combination.messageContext);
if (currentNode.connectedNodes[0] == null && currentNode.connectedNodes[1] == null) {
currentNode = tree.root;
continue;
}
}
for (Node node : currentNode.connectedNodes) {
if (node != null) {
System.out.print(node.value + " ");
} else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode, x);
}
Now try the code it is resetting to root as expected.
Given a generic tree implemented as a root node with a list of sons, which sons are nodes and again each node has a list of its sons.
__A__
/ | \
B C D
| / \
E F G
The node A has a list of its sons: B, C, D
B, C, D also have a list of their sons: B --> E ; C --> F, G ; D --> null ;
I will explain my idea of the algorithm, you can fix it or give me another completely new idea.
public Integer level(T dato) {...}
Traverse the tree adding to the queue each node of the tree or adding a "null" if the last node added is the last node of the level. Null is an identifier in the queue to know where the level has ended.
My problem is that I don't know exactly where to put the identifier after the first time.
Here is some of the code:
public Integer level(T data){
int inclu= this.include(data);
if (inclu==-1) { // if the tree doesn't include the data
return -1;
} else {
return inclu; // returns the level
}
}
public Integer include( T data ) { // returns the level where the data is
Integer inclu = -1; // -1 if the data is not included
if (this.getDataRoot()==data){
return 0; // The root of the tree has the data
}
else {
LinkedList<GenericNode<T>> queue = new LinkedList<GenericNode<T>>();
GenericNode<T> tree = new GenericNode<T>();
int level=1;
queue.addAtBeginning(this.getRoot());
queue.addAtBeginning(null);
while (queue.size()>0 && inclu==-1) {
if(queue.element(queue.size())!=null) { // if it is not the end of the level then dequeue
tree.setData(queue.element(queue.size()).getData()); //queue.element(position) returns the element in that position
tree.setListOfSons(queue.element(queue.size()).getSons());
if (tree.getSons()!=null) { // if the tree has sons
int i=1;
while(i<=tree.getSons().size() && inclu==-1) {
queue.addAtBeginning(tree.getSons().element(i));
if (tree.getSons().element(i).getData()==data) // if I found the data I'm looking for
inclu=level;
i++; // counter
}
}
} else { // if it is the end of the level (means the queue gave me a null)
level++;
}
queue.delete(queue.size()); //ending the dequeue process
} //end while
} // end main else
return inclu; //returns the summation of the levels or 0 if it was found at the root of the tree or -1 if the data was not found
}
I wrote a class that returns the level of target node in specific tree.
import java.util.LinkedList;
import java.util.List;
public class TreeLevel {
public static class Node {
public Node(String data) { this.data = data ; };
public String data;
public List<Node> childs = new LinkedList<Node>();
}
public static Integer level(Node tree, Node target){
return level(tree, target, 0);
}
private static Integer level(Node tree, Node target, int currentLevel) {
Integer returnLevel = -1;
if(tree.data.equals(target.data)) {
returnLevel = currentLevel;
} else {
for(Node child : tree.childs) {
if((returnLevel = level(child, target, currentLevel + 1)) != -1){
break;
}
}
}
return returnLevel;
}
public static void main(String[] args) {
Node a = new Node("A");
Node b = new Node("B");
Node c = new Node("C");
Node d = new Node("D");
Node e = new Node("E");
Node f = new Node("F");
Node g = new Node("G");
// childs of a:
a.childs.add(b);
a.childs.add(c);
a.childs.add(d);
// childs of b:
b.childs.add(e);
// childs of c:
c.childs.add(f);
c.childs.add(g);
// childs of d:
// d.childs = null or simply d.childs.length() is 0
Node target = new Node("G");
Integer level = level(a, target);
System.out.println("level [" + level + "]");
}
}
I think I can give you a simple code for this question. You can change the it according to your code.
public Integer include( T data ) { // returns the level where the data is
Integer inclu = -1; // -1 if the data is not included
if (this.getDataRoot() == data){
return 0; // The root of the tree has the data
}
return level(this.getRoot(), data, 1);
}
//Find data in a tree whose root is Node
//If not found, return -1
public int level(T node, T data, int level) {
if (!node.hasChildren()) {
return -1;
}
for (T child : node.getChildren()) {
if (child.getData == data) {
return level; //Aha!!! found it
} else {
int l = level(child, data, level + 1); /// find in this sub-tree
if (l != -1) {
return l;
}
}
}
return -1; /// Not found in this sub-tree.
}
P.S : == is used to compare, which is not good. .equals() should be used.
I implemented an algorithm in Java. I coded two versions:
one where I initialized the data structures in the constructor,
and
one where I parsed a textfile and initialized the data structure from the input
The strange thing is that I got different behaviour from the two versions, and can hardly understand how.
Why do I get different behaviour?
The algorithm is a first part of Depth-First Search. A set of nodes should be visited and printed only once. In my version where I read from a textfile, the first node is printed twice. The program uses recursion.
Here is the output, the code is below. The first four lines prints the data structures, then is each first-visit-of-a-node printed, and a counter. The counter should only go to 2 not 3.
Output, when read from textfile:
>java GraphStart ex1.txt
Node 1
Node 2
Edge: Node 1 -- Node 2
Edge: Node 2 -- Node 1
Start on Node 1
Node 1 Counter: 1
Node 2 Counter: 2
Node 1 Counter: 3
Output, when initialized in constructor:
Node 1
Node 2
Edge: Node 1 -- Node 2
Edge: Node 2 -- Node 1
Start on Node 1
Node 1 Counter: 1
Node 2 Counter: 2
Depth-First Search - initialized in contructor:
public class DepthFirstSearch {
private final static LinkedList<Node> nodes = new LinkedList<Node>();
private static LinkedList[] edges = new LinkedList[0];
public DepthFirstSearch() {
Node node1 = new Node(1);
Node node2 = new Node(2);
nodes.add(node1);
nodes.add(node2);
edges = Arrays.copyOf(edges, 1);
edges[0] = new LinkedList<Edge>();
edges[0].add(new Edge(node1, node2));
edges = Arrays.copyOf(edges, 2);
edges[1] = new LinkedList<Edge>();
edges[1].add(new Edge(node2, node1));
DFS.startDFS(nodes, edges);
}
public static void main(String[] args) {
new DepthFirstSearch();
}
}
Depth-First Search - initialized from textfile:
public class GraphStart {
private final static LinkedList<Node> nodes = new LinkedList<Node>();
private static LinkedList[] edges = new LinkedList[0];
public GraphStart(String fileName) {
scanFile(fileName);
DFS.startDFS(nodes, edges);
}
// Parse a textfile with even number of integers
// Add the nodes and edges to the datastructures
private static void scanFile(String filename) {
try {
Scanner sc = new Scanner(new File(filename));
while(sc.hasNextInt()){
Node startNode = new Node(sc.nextInt());
if(sc.hasNextInt()) {
Node endNode = new Node(sc.nextInt());
if(!nodes.contains(startNode)){
nodes.add(startNode);
//EDIT
System.out.println("Added " + startNode);
// Grow the Edge-array and initialize the content
if(edges.length < startNode.getNr())
edges = Arrays.copyOf(edges, startNode.getNr());
edges[startNode.getNr()-1] = new LinkedList<Edge>();
}
if(!nodes.contains(endNode)){
nodes.add(endNode);
//EDIT
System.out.println("Added " + endNode);
// Grow the Edge-array and initialize the content
if(edges.length < endNode.getNr())
edges = Arrays.copyOf(edges, endNode.getNr());
edges[endNode.getNr()-1] = new LinkedList<Edge>();
}
// Add the Edge
edges[startNode.getNr()-1].add(new Edge(startNode, endNode));
}
}
} catch (FileNotFoundException e) {
System.out.println("Can not find the file:" + filename);
System.exit(0);
}
}
public static void main(String[] args) {
if(args.length==1) {
new GraphStart(args[0]);
} else {
System.out.println("Wrong argument. <filename>");
}
}
}
Textfile for input:
1 2
2 1
It represents the Edge from Node 1 to Node 2, and the Edge from Node 2 to Node 1.
The algorithm is implemented in a static file, used by both versions.
DFS - the algorithm:
public class DFS {
private static int counter = 0;
private static LinkedList<Node> nodes;
private static LinkedList[] edges;
public static void startDFS(LinkedList<Node> ns, LinkedList[] es) {
nodes = ns;
edges = es;
/* Print the data structures */
printList(nodes);
printEdges(edges);
for(Node n : nodes) {
if(!n.isVisited()) {
System.out.println("\nStart on "+n);
dfs(n);
}
}
}
private static void dfs(Node n) {
counter++;
n.visit();
System.out.println(n + " Counter: " + counter);
for(Object o : edges[n.getNr()-1]) {
if(!((Edge)o).getEnd().isVisited()) {
dfs(((Edge)o).getEnd());
}
}
private static void printList(LinkedList<?> list) {
for(Object obj : list)
System.out.println(obj);
}
private static void printEdges(LinkedList[] edges) {
for(LinkedList list : edges) {
System.out.print("Edge: ");
for(Object o : list) {
System.out.print(o);
}
System.out.println("");
}
}
}
EDIT: Added code listings of Node and Edge.
Node:
public class Node {
private final int nr;
private boolean visited = false;
public Node(int nr) {
this.nr = nr;
}
public int getNr() { return nr; }
public boolean isVisited() { return visited; }
public void visit() { visited = true; }
#Override
public boolean equals(Object obj) {
if(obj instanceof Node)
return ((Node)obj).getNr() == nr;
else
return false;
}
#Override
public String toString() {
return "Node " + nr;
}
}
Edge:
public class Edge {
private final Node startNode;
private final Node endNode;
public Edge(Node start, Node end) {
this.startNode = start;
this.endNode = end;
}
public Node getStart() { return startNode; }
public Node getEnd() { return endNode; }
public String toString() {
return startNode + " " +
"--" + " " +
endNode;
}
}
Sorry for the very long code listings. I tried to isolate my problem and also show a runnable program.
Without seeing the code for Node, my guess is that it isn't implementing hashCode() and equals() or that these aren't implemented correctly.
So for example:
if(!nodes.contains(startNode)){
nodes.add(startNode);
Will be doing the containment check with reference equality (==) instead of anything logical. So the fact that you've create three different node instances will not resolve even though two are "the same".
...and that's why the static method version works because you only have two node instances.
Edit: the above was a good guess but reading deeper into the code I think it has to do with the fact that visit state is kept right on the nodes instead of in a separate visited collection. You have three node instances in your graph even if only two are in the nodes list. One of the edges is pointing to the third node instance (the other one with a '1')... since the visited() method was never called on that one (because it was called on the first '1' instance) then isVisited() will likely return false (can't say for sure because I don't know your Node implementation).
You did not show the implementation for Node, but I would guess that you did not override equals() for it. This will lead nodes.contains(node) to return false and more nodes to be added to the collection than wanted. (The file reading loop creates a fresh start- and endNode everytime through the loop.)
Your constuctor version simply uses 2 unique nodes, which gives the different result.
Implementing Node.equals() will probably solve your issue.
Your scanFile() method creates three nodes - two containing the integer 1, and one containing the integer 2.