I was trying to implement a class Node to build a tree of Nodes. Basically, each Node can have children, so if I specify multiple nodes I can build a tree out of it.
As an example:
node1 (the root) has node2 and node3 as children
node2 has node4 and node5 as children
The problem I am having problems to solve is to build this tree and find all children of a given element (in this case node1 would have 4 children, since it has node2 and node3 in the first place, and node2 has 2 children, so in total 4).
Does anyone have any suggestion?
EDIT:
package ex1;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Node {
private String name;
private String description;
private ArrayList<Node> children = new ArrayList<>();
Node(String name, String description){
this.name = name;
this.description = description;
}
private void setName(String name){
this.name = name;
}
private void setDescription(String description) {
this.description = description;
}
public void addChildren(Node child) {
this.children.add(child);
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public boolean hasDescription() {
return !description.isEmpty();
}
public Collection<Node> getChildren() {
return this.children;
}
/*
public Node findNodeByName(String name, Node t) {
if (t.getName().equals(name))
return t;
t.getChildren().forEach(node -> node.findNodeByName(name,node));
return null;
}*/
public Node findNodeByName(String name, Node t){
if(t.getName().equals(name)){
return t;
}
else if (t.getChildren().size() != 0){
for(Node c: children){
Node ret = c.findNodeByName(name,c);
if(ret != null){
return ret;
}
}
}
return null;
}
// IMPORTANT: Don't change this method!
private String toString(int indentNo) {
String indent = "\t".repeat(indentNo);
StringBuffer b = new StringBuffer();
b.append(indent);
b.append(getClass().getSimpleName() + " '" + getName() + "' ");
if (hasDescription()) {
b.append("(description: " + getDescription() + ")");
}
b.append("\n");
for (Node node : getChildren()) {
b.append(node.toString(indentNo + 1));
}
return b.toString();
}
#Override
public String toString() {
return toString(0);
}
}
Method where I make use of the class:
Path path = Path.of(pathname);
String fileContent = null;
try {
fileContent = Files.readString(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
List<String> lines = new ArrayList<>(Arrays.asList(fileContent.split("\n")));
String[] firstLine = lines.get(0).split(",");
Node parentNode = new Node(firstLine[0], firstLine[1]);
lines.remove(0);
/* This was just to test findNodeByName
for(String line: lines) {
String[] params = line.split(",");
System.out.println(params[2] + ": " + (parentNode.findNodeByName(params[2], parentNode) != null));
}*/
//Now we read all remaining data
Node tmpNode;
for(String line: lines) {
String[] params = line.split(",");
if (parentNode.findNodeByName(params[2])==null || parentNode.findNodeByName(params[0])!=null) //if parent was not found or name already exists
throw new IOException();
tmpNode = parentNode.findNodeByName(params[2]);
tmpNode.addChildren(new Node(params[0],params[1]));
}
CSV file I am getting the data from:
uni,"This is my university folder",
firstyear,,uni
secondyear,,uni
analysis,"folder for the analysis course",firstyear
ai,"folder for the artificial intelligence course",secondyear
db,"folder for the database course",firstyear
Here is some sample code that could help (explanation below):
Main class:
class Main {
public static void main(String[] args) {
Node v1 = new Node(1);
Node v2 = new Node(2);
Node v3 = new Node(3);
Node v4 = new Node(4);
Node v5 = new Node(5);
v1.addChild(v2);
v1.addChild(v3);
v2.addChild(v4);
v2.addChild(v5);
v1.printChildren();
}
}
Node class:
import java.util.*;
class Node{
private int val;
private ArrayList<Node> children = new ArrayList<Node>();
public Node(int v){
val = v;
}
public void addChild (Node c){
children.add(c);
}
public void printChildren(){
if (children.size() != 0){
System.out.print("Children of Node " + getValue() + ": ");
for(Node c: children){
System.out.print("Node " + c.getValue() + " ");
}
System.out.println();
for(Node c: children){
c.printChildren();
}
}
}
public int getValue(){
return val;
}
}
Output:
Children of Node 1: Node 2 Node 3
Children of Node 2: Node 4 Node 5
Ok so in our node class, let's say each node will have an integer value, val. That is our first private instance variable. Second, each node will have a list of children nodes, children.
When we first declare our nodes, they will have integer values, as shown in our constructor.
After we define our nodes, we can add some nodes as children to other nodes (v2 and v3 are children to v1, and v4 and v5 are children to v2).
Now we need to print them. We will use a recursive approach for this. If the node we are printing the children of has children (the length of our children ArrayList is nonzero), then we will first iterate through that list, and print out the children of our current node. Afterwards, we again iterate through each child and use the same method (recursion) to print out the children of that node.
I hope this helped! Please let me know if you need any further help or clarification :)
EDIT:
Added a getName() method:
public String getName(){
return "Node" + getValue();
}
Added the requested method:
public Node findChildNodeByValue(int v){
if(getValue() == v){
System.out.println(getName() + " has the value");
return new Node(getValue());
}
else if (children.size() != 0){
for(Node c: children){
Node ret = c.findChildNodeByValue(v);
if(ret != null){
return ret;
}
}
}
return null;
}
Quick Explanation: Very similar to the original method, we use a recursive approach to iterate through each nodes' children: Once we reach a node with no more children, we return null. Once we reach the node with the given value, we return a copy of that node, which will be sent back to wherever the function was called..
Also edited main method:
Node v1 = new Node(1);
Node v2 = new Node(2);
Node v3 = new Node(3);
Node v4 = new Node(4);
Node v5 = new Node(5);
v1.addChild(v2);
v1.addChild(v3);
v2.addChild(v4);
v2.addChild(v5);
// v1.printChildren();
Node valNode = v1.findChildNodeByValue(5);
System.out.println(valNode.getName());
Output:
Node5 has the value
Node5
SECOND EDIT:
Change the method to look like this:
public Node findNodeByName(String name){
if(getName().equals(name)){
Node t = new Node(getName(), getDescription());
return t;
}
else if (getChildren().size() != 0){
for(Node c: children){
Node ret = c.findNodeByName(name);
if(ret != null){
return ret;
}
}
}
return null;
}
The main method should look like this:
Node v1 = new Node("a","aa");
Node v2 = new Node("b","bb");
Node v3 = new Node("c","cc");
Node v4 = new Node("d","dd");
Node v5 = new Node("e","ee");
v1.addChildren(v2);
v1.addChildren(v3);
v2.addChildren(v4);
v2.addChildren(v5);
System.out.println(v1.findNodeByName("e"));
Output:
Node 'e' (description: ee)
THIRD EDIT:
Added a new method:
public void setChildren(ArrayList<Node> c){
children = c;
}
Edited method:
public Node findNodeByName(String name){
if(getName().equals(name)){
Node t = new Node(getName(), getDescription());
t.setChildren(getChildren());
return t;
}
else if (getChildren().size() != 0){
for(Node c: children){
Node ret = c.findNodeByName(name);
if(ret != null){
return ret;
}
}
}
return null;
}
Main Method:
Node v1 = new Node("a","aa");
Node v2 = new Node("b","bb");
Node v3 = new Node("c","cc");
Node v4 = new Node("d","dd");
Node v5 = new Node("e","ee");
Node v6 = new Node("f","ff");
v1.addChildren(v2);
v1.addChildren(v3);
v2.addChildren(v4);
v2.addChildren(v5);
v4.addChildren(v6);
Node vNew = v1.findNodeByName("d");
System.out.println(vNew);
System.out.println(vNew.getChildren());
Output:
Node 'd' (description: dd)
Node 'f' (description: ff)
[Node 'f' (description: ff)
]
The return value of the recursive method call is dismissed.
The line
t.getChildren().forEach( node -> findNodeByName(name, node));
induces the recursive invocation, but the return value is not used to form the return value of the enclosing method.
Instead we need something like
for (Node node : t.getChildren()) {
Node result = findNodeByName(name, node);
if (null != result) {
return result;
}
}
or with streams
return t.getChildren()
.map(node -> findNodeByName(name, node))
.filter(Objects::nonNull)
.findAny();
As per your requirement, you are looking for all descendants / children-of-children of a particular node. Then breadth-first depth-search is fit more to this use case. There are already tons of discussions around these algorithms. For instance:
Breadth First Search and Depth First Search
You are already thinking in the right direction related to its DataStructure. One thing I would suggest use java generics so that it can support multiple data-type as needed.
class Node<T> {
T value;
List<T> children;
Node(T t) {
this.value = t;
children = new ArrayList<T>();
}
void addChild(T child) {
children.add(child);
}
}
Related
trying to convert a level order input to a N-Ary tree. Where levels are separated by a null. Example.
Input: [1, null, 2,3,4, null,5,6,null,7,8,null,9,10]
Code is expected to build a tree and finally print the preorder of the same for validation.
Output: [1,2,5,6, 3,7,8,4,9,10]
Not getting the desired output. Also this needs to be solved iteratively and recursion may not be used. Below is the full code. Added some print statement to ease debugging.
enter code here
package AllTree;
import java.util.*;
public class ListToNArrayTree {
public static class Node{
public int val;
public ArrayList<Node> children = new ArrayList<>();
public Node (int val){
this.val = val;
}
public Node (int val, ArrayList<Node> children){
this.val = val;
this.children = children;
}
public String toString(){
return " " + val;
}
public ArrayList<Node> getChildren() {
return children;
}
public void setChildren(ArrayList<Node> children) {
this.children = children;
}
}
public static Node buildTree(List<Integer> dataAsList){
/*Check if the input is valid to create a tree example {1, null, 2,3,4, null,5,6,null,7,8,null,9,10, null};
Above is a level order so null is mandatory # position 1.
*/
if (dataAsList.isEmpty() || dataAsList.get(0) == null|| dataAsList.get(1) !=null){
System.out.println ("Invalid data to construct a tree");
return null;
}
/*Create queue to hold all values from input*/
Queue<Integer> dataAsQueue = new LinkedList<>();
for (Integer data: dataAsList) {
dataAsQueue.add(data);
}
/*Create queue to hold the nodes which will be retrieved in FIFO to add corresponding children*/
Queue<Node> dataAsTree = new LinkedList<>();
Node root = new Node(dataAsQueue.poll()); // to poll the root element
dataAsQueue.poll(); // to poll the null - as after this is the beginning of the second level of the tree
dataAsTree.add(root);
root = dataAsTree.poll();
Node parent = root;
while (!dataAsQueue.isEmpty()) {
Node parent_ = parent;
Integer childInt= dataAsQueue.poll();
if (childInt != null){
parent_.getChildren().add(new Node(childInt));
dataAsTree.add(new Node(childInt));
}
else{
parent = dataAsTree.poll();
}
System.out.println ("Current parent " + parent_ + " with children" + parent_.children);
}
return root;
}
public static void main(String[] args){
List<Integer> dataAsList = Arrays.asList(1, null, 2,3,4, null,5,6,null,7,8,null,9,10);
// Node root = buildTree(dataAsList);
System.out.println ("PreOrder Sorting" + preorder( buildTree(dataAsList)));
}
public static List<Integer> preorder(Node root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
preorderhelper(root, res);
return res;
}
private static void preorderhelper(Node root, LinkedList<Integer> res) {
if (root == null) {
return;
}
res.add(root.val);
if (root.children != null) {
for (Node c : root.children) {
preorderhelper(c, res);
}
}
}
}
Given two binary trees with head reference as T and S having at most N nodes. The task is to check if S is present as subtree in T.
A subtree of a tree T1 is a tree T2 consisting of a node in T1 and all of its descendants in T1.
Why my approach is fail?
my algo is :-
Find inorder and preorder traversals of T, store them in two lists.
Find inorder and preorder traversals of S, store them in two lists.
If inorder and preorder lists of T occurs in inorder and preorder lists of S then return true else false.
import java.util.LinkedList;
import java.util.Queue;
import java.io.*;
import java.util.*;
class Node{
int data;
Node left;
Node right;
Node(int data){
this.data = data;
left=null;
right=null;
}
}
class GfG {
static Node buildTree(String str){
if(str.length()==0 || str.charAt(0)=='N'){
return null;
}
String ip[] = str.split(" ");
// Create the root of the tree
Node root = new Node(Integer.parseInt(ip[0]));
// Push the root to the queue
Queue<Node> queue = new LinkedList<>();
queue.add(root);
// Starting from the second element
int i = 1;
while(queue.size()>0 && i < ip.length) {
// Get and remove the front of the queue
Node currNode = queue.peek();
queue.remove();
// Get the current node's value from the string
String currVal = ip[i];
// If the left child is not null
if(!currVal.equals("N")) {
// Create the left child for the current node
currNode.left = new Node(Integer.parseInt(currVal));
// Push it to the queue
queue.add(currNode.left);
}
// For the right child
i++;
if(i >= ip.length)
break;
currVal = ip[i];
// If the right child is not null
if(!currVal.equals("N")) {
// Create the right child for the current node
currNode.right = new Node(Integer.parseInt(currVal));
// Push it to the queue
queue.add(currNode.right);
}
i++;
}
return root;
}
static void printInorder(Node root){
if(root == null)
return;
printInorder(root.left);
System.out.print(root.data+" ");
printInorder(root.right);
}
public static void main (String[] args) throws IOException {
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
int t=Integer.parseInt(br.readLine());
while(t-- > 0){
String tt= br.readLine();
Node rootT = buildTree(tt);
String s= br.readLine();
Node rootS = buildTree(s);
// printInorder(root);
Solution tr=new Solution();
boolean st=tr.isSubtree(rootT, rootS);
if(st==true){
System.out.println("1");
}else{
System.out.println("0");
}
}
}
}// } Driver Code Ends
class Solution {
// algo implementation is started from here.
public static void preorder(Node root , ArrayList<Integer>al )
{
if(root!=null)
{
al.add(root.data);
preorder(root.left, al);
preorder(root.right, al);
}
}
public static void inorder(Node root, ArrayList<Integer>al)
{
if(root!=null)
{
inorder(root.left, al);
al.add(root.data);
inorder(root.right, al);
}
}
public static boolean isSubtree(Node t, Node s)
{
ArrayList<Integer> alt1 = new ArrayList<>();
ArrayList<Integer>alt2 = new ArrayList<>();
ArrayList<Integer> als1 = new ArrayList<>();
ArrayList<Integer>als2 = new ArrayList<>();
preorder(t,alt1);
inorder(t,alt2);
preorder(s,als1);
inorder(s,als2);
if(alt1.containsAll(als1) && alt2.contains(als2))
return true;
return false;
}
}
~~~
you approch is right, you are checking is arraylist of S has all the values present in array list of T
just change this part
als1.containsAll(alt1) && als2.contains(alt2) to if(alt1.containsAll(als1) && alt2.contains(als2)) return true;
I have the following data structure:
This tree stores only characters in lowercase.
I'm trying to build a method that finds the longest word in the tree recursively.
I have difficulty to build this method that checks each branch of the nodes recursively.
Here the given classes I'm using, showing only the relevant methods:
public class Tree {
private final Node root;
public Tree() {
root = new Node('0');
}
private String getWordOfBranch(final Node[] nodes, final int i) {
if (nodes[i] == null) {
return "";
}
if (nodes[i].isLeaf()) {
return String.valueOf(nodes[i].getValue());
}
return nodes[i].getValue() + getWordOfBranch(nodes[i].children, i);
}
public class Node {
private final char value;
protected Node[] children;
public Node(final char value) {
this.value = value;
children = new Node[26];
}
public boolean isLeaf() {
for (final Node child : children) {
if (child != null) {
return false;
}
}
return true;
}
public char getValue() {
return value;
}
Well, in this case, you are only taking the word starting at a specific position i. What you should be doing is looping through all of the children and finding the longest word out of all of the children. Also, your node class should not be having a set amount of children, but instead a dynamically sized list of children, using something like an ArrayList to store the children, since each node does not have to have a specific set of children.
public class Node {
private final char value;
protected ArrayList<Node> children;
public Node(final char value) {
this.value = value;
children = new ArrayList<Node>();
}
public boolean isLeaf() {
for (final Node child : children) {
if (child != null) {
return false;
}
}
return true;
}
public char getValue() {
return value;
}
public ArrayList<Node> getChildren() {
return children;
}
public String getLargestWord(Node root) {
if (root.isLeaf()) {
return String.valueOf(root.getValue());
}
else {
String longest = "";
for (Node child : root.getChildren()) {
String longWordInChild = getLongestWord(child);
if (longWordInChild.length() > longest.length()) {
longest = longWordInChild;
}
}
return root.getValue() + longest;
}
}
I made some changes to your code.
First the Node class.
import java.util.ArrayList;
import java.util.List;
public class Node {
private final char value;
protected List<Node> children;
public Node(char letter) {
value = letter;
children = new ArrayList<>();
}
private static boolean isValidValue(Node node) {
boolean isValid = false;
if (node != null) {
char ch = node.getValue();
isValid = 'a' <= ch && ch <= 'z';
}
return isValid;
}
public boolean addChild(Node child) {
boolean added = false;
if (child != null) {
if (isValidValue(child)) {
boolean found = false;
for (Node kid : children) {
found = kid != null && kid.getValue() == child.getValue();
if (found) {
break;
}
}
if (!found) {
added = children.add(child);
}
}
}
return added;
}
public List<Node> getChildren() {
return children;
}
public char getValue() {
return value;
}
}
I used List for the children, rather than an array, because an array has a fixed size and a List does not.
Now the Tree class. Note that I added a main() method to the class just for testing purposes. The main() method creates the tree structure in the image in your question.
A tree data structure has levels and also has leaves. A leaf is a node in the tree that has no child nodes. Hence every leaf in your tree is the last letter of a word. The leaves at the highest level represent the longest words. (Note that the level of the root node in the tree is zero.)
import java.util.ArrayList;
import java.util.List;
public class Tree {
private int longest;
private List<String> words;
private Node root = new Node('\u0000');
public List<String> getWords() {
return words;
}
public Node getRoot() {
return root;
}
public void visit() {
visit(root, 0, new StringBuilder());
}
public void visit(Node node, int level, StringBuilder word) {
if (node != null) {
word.append(node.getValue());
List<Node> children = node.getChildren();
if (children.size() == 0) {
if (level > longest) {
longest = level;
words = new ArrayList<>();
}
if (level == longest) {
words.add(word.toString());
}
}
else {
for (Node child : children) {
word.delete(level, word.length());
visit(child, level + 1, word);
}
}
}
}
/**
* For testing only.
*/
public static void main(String[] args) {
Tree tree = new Tree();
Node root = tree.getRoot();
Node j = new Node('j');
root.addChild(j);
Node r = new Node('r');
root.addChild(r);
Node a = new Node('a');
j.addChild(a);
Node v = new Node('v');
a.addChild(v);
Node a2 = new Node('a');
v.addChild(a2);
Node a3 = new Node('a');
r.addChild(a3);
Node o = new Node('o');
r.addChild(o);
Node d = new Node('d');
a3.addChild(d);
Node n = new Node('n');
a3.addChild(n);
Node d2 = new Node('d');
n.addChild(d2);
Node u = new Node('u');
a3.addChild(u);
Node m = new Node('m');
u.addChild(m);
Node s = new Node('s');
o.addChild(s);
Node e = new Node('e');
s.addChild(e);
tree.visit();
System.out.println(tree.getWords());
}
}
Method visit(Node, int, StringBuilder) is the recursive method. It traverses every path in the tree and appends the characters in each node to a StringBuilder. Hence the StringBuilder contains the word obtained by traversing a single path in the tree - from the root to the leaf.
I also keep track of the node level since the highest level means the longest word.
Finally I store all the longest words in another List.
Running the above code produces the following output:
[java, rand, raum, rose]
I am just getting started with functional programming in Java. I'd like some help with a simple exercise to get up to speed.
Suppose one has the following two interfaces:
interface P {
boolean filter(int v);
}
interface F {
int apply(int v);
}
and one is required to create a map function that takes a function f as an argument and returns a Node that applies f to all elements. Secondly, one is required to create a filter function that returns a Node with all elements that match a predicate p within the Following class:
public class Node {
private int item;
private Node next;
public Node(int item, Node next){
this.item = item;
this.next = next;
}
/* Create a new Node that applies function f to all elements */
public Node map(F f){
}
/* Creates a new Node with all elements that match predicate p */
public Node filter(P p){
}
}
public Node map(F f){
Node start = new Node(f.apply(item), null);
Node current = start;
for(Node originalNode = this.next; originalNode != null; originalNode = originalNode.next) {
Node copyOfNextNode =new Node(f.apply(originalNode.item), null);
current.next = copyOfNextNode;
current = current.next;
}
return start;
}
/* Creates a new Node with all elements that match predicate p */
public Node filter(P p){
Node start = null;
Node current = null;
for(Node originalNode = this; originalNode != null; originalNode = originalNode.next) {
if(p.filter(originalNode.item)) {
Node copyOfNextNode =new Node(originalNode.item, null);
if(current == null) {
current = copyOfNextNode;
start = current;
} else {
current.next = copyOfNextNode;
current = current.next;
}
}
}
return start;
}
I've been working on some code that recursively iterates through a trie filled with words.
There are a lot of problems with this right now, but ignoring those, I was wondering why "?"s are printing out here when I have no "?"s in my trie or any print statements?
Here's my code for the recursion portion of my work. Please ask if you need anything else.
public String recurse(Node n){//RECURSION
String build = "";
build += n.getVal();
System.out.print(build);
if(n.getChild() != null){
recurse(n.getChild());
}
if(n.getSibling() != null){
recurse(n.getSibling());
}
return build;
}
This is the output I'm currently getting:
duck^?free^?good^?real^?hum^?rtful^?duck^?free^?good^?real^?hum^?rtful^?
Any help is appreciated. Thanks a lot.
EDIT
Here are the words in my trie(i'm using a small number of words to test first):
argument
bash
cow
duck
free
good
real
hum
ask
allow
hurtful
Here is my Node class:
public class Node{
private Node child;
private Node sibling;
private char value;
public Node(char val){
value = val;
}
public char getVal(){
return value;
}
public Node getChild(){
return child;
}
public Node getSibling(){
return sibling;
}
public void setVal(char val){
value = val;
}
public void setChild(Node nextReference){
child = nextReference;
}
public void setSibling(Node nextReference){
sibling = nextReference;
}
}
I filled the DLB trie with the code like this:
public boolean add(String s){
if (s == null)
return false;
s = s + SENTINEL; //sentinel is '^'
StringCharacterIterator iterator = new StringCharacterIterator(s);
if(root == null){//this is if there are NO values in the trie
root = new Node(iterator.current());
Node currentNode = root;
iterator.next();
while(iterator.getIndex() < iterator.getEndIndex()){
Node newNode = new Node(iterator.current());
currentNode.setChild(newNode);
currentNode = currentNode.getChild();
iterator.next();
}
}else{
Node currentNode = root;
while(iterator.getIndex() < iterator.getEndIndex()){
while(iterator.current()!=currentNode.getVal()){
if(currentNode.getSibling() == null){
Node newNode = new Node(iterator.current());
currentNode.setSibling(newNode);
currentNode = currentNode.getSibling();
break;
}else{
currentNode = currentNode.getSibling();
}
}
iterator.next();
if(currentNode.getChild() == null){
Node newNode = new Node(iterator.current());
currentNode.setChild(newNode);
}
//iterator.next();
currentNode = currentNode.getChild();
}
}
return true;
}