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);
}
}
}
}
Related
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);
}
}
I am using a method DFS which marks the visited node as visited and puts the string into the result stack.
This is a DAG which mean two Nodes can point to the same node as long as its not pointing back and creating a cycle. I created a Test case to create a cycle.
I am pointing a -> b -> c -> d -> e then I point z -> d and z -> d and then z -> a
I am pretty sure the culprit is the DFS algo called dfs. I have tried changing it but I am having a hard time figuring out the logic.
I node has a boolean called visited which I set to true and the I set to false after I have traversed its children. If I end up running into a true node then I print cyclic and end the program.
I am looking for guidance on a better way to implement this exact problem. Is there logical error in my dfs? I think thats where the problem lies.
package ChaseInterview;
import java.util.*;
public class ChaseInterview {
public static class Node<T> {
T val;
HashSet<Node<T>> adj = new HashSet<>();
boolean visited = false;
public Node(T val) {
this.val = val;
}
public Node() {
}
#Override
public String toString() {
return val.toString() + adj.toString();
}
}
public static class DAG<T> {
Node<T> root = new Node<T>();
HashMap<T, Node<T>> map = new HashMap<>();
public void DAG() {
}
public void add(T val) {
if (map.containsKey(val)) return;
Node<T> newNode = new Node<T>(val);
map.put(val, newNode);
root.adj.add(newNode);
}
public void add(T val1, T val2) {
Node<T> node1 = map.containsKey(val1) ? map.get(val1) : new Node<T>(val1);
Node<T> node2 = map.containsKey(val2) ? map.get(val2) : new Node<T>(val2);
if (!map.containsKey(val1)) root.adj.add(node1);
if (root.adj.contains(node2)) root.adj.remove(node2);
node1.adj.add(node2);
map.put(val1, node1);
map.put(val2, node2);
}
public String print() {
Stack<T> stack = new Stack<>();
dfs(stack, root);
StringBuilder res = new StringBuilder();
while (!stack.isEmpty()) {
res.append(stack.pop());
}
return res.reverse().toString();
}
public void dfs(Stack<T> stack, Node<T> root) {
if (root.visited) {
System.out.println("Cyclic");
System.exit(-1);
}
root.visited = true;
// populate stack
if (!(root.val == null) && !stack.contains(root.val)) stack.push(root.val);
// traverse nodes
if (!root.adj.isEmpty()) {
for (Node<T> node : root.adj) {
dfs(stack, node);
}
}
root.visited = false;
}
}
public static void main(String[] args) {
System.out.println("HelloWord");
DAG<Character> dag = new DAG<Character>();
dag.add('a', 'b');
dag.add('b', 'c');
dag.add('z');
dag.add('c', 'd');
dag.add('d', 'e');
dag.add('d', 'z');
dag.add('z', 'd');
dag.add('z', 'a');
//dag.add('b','a');
System.out.println(dag.map.size());
System.out.println(dag.print());
System.out.println(dag.map.size());
}
}
output:
6
6
I re-did the dfs and print methods to this:
new DFS:
if root visited then cycle exists
if stack contains root val then branch has been traversed. just return
mark root to visited
dfs adjacent nodes
push root val to stack
mark root unvisited
New print() // returns topsort I should change the name I know
make a result stack and string builder
loop through map.keySet
if key.val not in stack -> call dfs
pop stack to string builder
string
public String print() {
Stack<T> stack = new Stack<>();
StringBuilder res = new StringBuilder();
for(T val: map.keySet()){
if (!stack.contains(val)) dfs(stack,map.get(val));
}
while(!stack.isEmpty()) res.append(stack.pop());
return res.toString();
}
public void dfs(Stack<T> stack, Node<T> root) {
if (root.visited) {
System.out.println("Cycle at :" + root.val.toString());
System.exit(-1);
}
if (stack.contains(root.val)) return;
root.visited = true;
for (Node<T> n: root.adj) dfs(stack,n);
stack.add(root.val);
root.visited =false;
}
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 need to print all the nodes that are N level above all Leaf Nodes. I tried below approach, but now I am stuck and unable to proceed. Please help. I need to code only using Java 7 and no other versions.
For example, I have this path 1 --> 2 --> 3 --> 4, so in this case assuming 4 is my leaf node, node 3 is 1 level above 4 and node 2 is 2 levels above leaf node 4 and node 1 is 3 levels above leaf node 4.
Note: Please use only Java 7.
public class NNodeBeforeLeaf {
static Node root;
static class Node {
int data;
Node left, right;
Node(int data){
this.data = data;
left=right=null;
}
}
public static boolean isLeaf(Node n){
if(n.right == null && n.left == null)
return true;
return false;
}
public static void main(String[] args) {
int level = 2; // level N
root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(8);
print(root, 0, level);
}
public static void print(Node n, int currLevel, int level){
if(n == null){
return;
}
if(!isLeaf(n)){
print(n.left, currLevel + 1, level);
print(n.right, currLevel + 1, level);
}
printNode(n, currLevel, level);
}
public static void printNode(Node n, int currLevel, int level){}
}
You have a miss in your structure to do this a Node know its child but not is parent so you need to build a structure that will give you this link : here is my proposition : i build a map that give me the parent associate to a node with method buildParentMap this function already list all the leaf in one pass to avoid a double iteration on your tree then i use this map to go up as many time as asked on each leaf i list just before here is a snippet
be carefull this code work but there is no security if your are trying to upper that root or if the same node is present in too child (but 2 Node with the same data wont be a problem)
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
public class NNodeBeforeLeaf {
static Node root;
static class Node {
int data;
Node left, right;
Node(int data) {
this.data = data;
left = right = null;
}
#Override
public String toString() {
return "Node : " + data;
}
}
public static boolean isLeaf(Node n) {
if (n.right == null && n.left == null)
return true;
return false;
}
public static void main(String[] args) {
int level = 2; // level N
root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(8);
print(root, 0, level);
int levelToUp = 1;
HashSet<Node> result = getUpper(levelToUp, root);
System.out.println(Arrays.toString(result.toArray()));
}
private static HashSet<Node> getUpper(int levelToUp, Node node) {
HashMap<Node, Node> parenttMap = new HashMap<Node, Node>();
LinkedList<Node> leafs = new LinkedList<Node>();
buildParentMap(node, parenttMap, leafs);
HashSet<Node> result = new HashSet<>();
for (Node leaf : leafs) {
result.add(getUpperLevel(leaf, levelToUp, parenttMap));
}
return result;
}
private static Node getUpperLevel(Node leaf, int i, HashMap<Node, Node> parenttMap) {
Node tmp = leaf;
while (i > 0) {
i--;
tmp = parenttMap.get(tmp);
}
return tmp;
}
private static void buildParentMap(Node root2, HashMap<Node, Node> hashMap, LinkedList<Node> leaf) {
if (root2 == null) {
return;
} else if (isLeaf(root2)) {
leaf.add(root2);
} else {
hashMap.put(root2.left, root2);
buildParentMap(root2.left, hashMap, leaf);
hashMap.put(root2.right, root2);
buildParentMap(root2.right, hashMap, leaf);
}
}
public static void print(Node n, int currLevel, int level) {
if (n == null) {
return;
}
printNode(n, currLevel, level);
if (!isLeaf(n)) {
print(n.left, currLevel + 1, level);
print(n.right, currLevel + 1, level);
}
}
public static void printNode(Node n, int currLevel, int level) {
String output = "";
for (int i = 0; i < currLevel; i++) {
output += "\t";
}
System.out.println(output + n);
}
}
PLEASE READ MY COMMENT FIRST
Since the nodes in your program store data only for the nodes below them, I couldn't really find a way of actually going up the tree ':), but I could think of this work around, basically what you can do is, each time you need to go up by n levels you can traverse down from the root to (curLevel - n) here is a sample program that does this (it prints all the nodes at a level which is n above the current level, i hope this is what you meant):
class tree{
static class Node{
int data;
Node left;
Node right;
Node(int data){
this.data = data;
left = null;
right = null;
}
}
static Node root;
public static boolean isLeaf(Node n){
if(n.left == null && n.right == null)
return true;
return false;
}
public static void goDownTillLevel(Node n, int level){
int l = level;
if(n != null){
if(level == 0) {
System.out.println(n.data);
}
else{
if(!isLeaf(n)){
goDownTillLevel(n.left, --level);
level = l; //since by the time the above function calls finished, level had been reduced to 0
goDownTillLevel(n.right, --level);
}
}
}
}
public static void nLevelsAbove(Node n, int curLevel, int level){
goDownTillLevel(root, (curLevel - level - 1));
}
public static void main(String args[]){
int curLevel = 0;
root = new Node(1);
curLevel++;
root.left = new Node(2);
root.right = new Node(2);
curLevel++;
root.left.left = new Node(3);
root.left.right = new Node(3);
root.right.left = new Node(3);
Node n = new Node(3);
root.right.right = n;
curLevel++;
nLevelsAbove(n, curLevel, 1);
}
}
Though I'd like to add that if going up is one of your concerns, don't use this node structure, instead add another variable to the node, a reference to the node right above it, that way this could be made much easier and shorter.
The output of the above code is:
2
2
I think that the implementation of public static boolean isLeaf(Node n) is wrong, it should check only if right is null otherwise it is not a node, either a leaf
To get the current level of node, you can try with this code
int level = 0;
while(node.right != null) {
level++;
node = node.right;
}
System.out.println("current level node: " + level);
Your structure is not able to determine the height of the current node, except when traversing from bottom to top. In order to achieve this, you have to traverse to the leafs first.
Each recursion (bottom up now) should then return it's heights. As youre not stating if your tree is a full binary tree, a node can have multiple heights depending on his children. If the heights match the desired height, the node can be printed.
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class NNodeBeforeLeaf {
static Node root;
static class Node {
int data;
Node left, right;
Node(int data) {
this.data = data;
left = right = null;
}
}
public static boolean isLeaf(Node n) {
return n.right == null && n.left == null;
}
public static void main(String[] args) {
int level = 2; // level N
root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(8);
print(root, level);
}
public static void print(Node n, int level) {
traversAndPrint(n, level);
}
private static Set<Integer> traversAndPrint(Node n, int levelToPrint) {
if (isLeaf(n)) return Collections.singleton(0); // We are a leaf, so we have height 0
final Set<Integer> childrenHeights = new HashSet<>();
// are no leaf, so we have to get the heights of our children
if (n.right != null) childrenHeights.addAll(traversAndPrint(n.right, levelToPrint));
if (n.left != null) childrenHeights.addAll(traversAndPrint(n.left, levelToPrint));
assert !childrenHeights.isEmpty();
// And increase these heights
final Set<Integer> selfHeights = new HashSet<>();
for (Integer childrenHeigth : childrenHeights) {
final int selfHeight = childrenHeigth + 1;
selfHeights.add(selfHeight);
}
// If we have the desired height, print
if (selfHeights.contains(levelToPrint)) printNode(n);
return selfHeights; // return our heights
}
public static void printNode(Node n) {
// Do whatever you want
System.out.println(n.data);
}
}
I found another approach. I put all nodes in a list. For each level up I remove the leaf nodes in that list. A leaf node in the list is defined as a node with left=null and right=null or if they are not null left and right should not be in the list. After the level ups I print the now leaf nodes in the list.
public class NNodeBeforeLeaf {
static Node root;
static class Node {
int data;
Node left, right;
Node(int data) {
this.data = data;
left = right = null;
}
}
public static boolean isLeaf(Node n) {
if ((n.right == null) && (n.left == null)) {
return true;
}
return false;
}
public static void main(String[] args) {
int level = 2; // level N
root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(8);
printNodes(getNodesNLevelAboveLeafs(root, level));
}
public static void printNodes(List<Node> nodes) {
for (Node n : nodes) {
System.out.println(n.data);
}
}
public static List<Node> getNodesNLevelAboveLeafs(Node root, int level) {
List<Node> allNodes = listAllNodes(root);
for (int i = 0; i < level; i++) {
allNodes.removeAll(getLeafNodes(allNodes));
}
return getLeafNodes(allNodes);
}
private static List<Node> getLeafNodes(List<Node> allNodes) {
List<Node> leafs = new ArrayList<>();
for (Node n : allNodes) {
if (((n.left == null) || !allNodes.contains(n.left))
&& ((n.right == null) || !allNodes.contains(n.right))) {
leafs.add(n);
}
}
return leafs;
}
private static List<Node> listAllNodes(Node node) {
List<Node> nodes = new ArrayList<>();
nodes.add(node);
if (node.left != null) {
nodes.addAll(listAllNodes(node.left));
}
if (node.right != null) {
nodes.addAll(listAllNodes(node.right));
}
return nodes;
}
}