Recursion of Level Order Traversal of N-ary tree - java

I am currently working on N-ary trees and I stumbled upon Level Order Traversal. It seemed very easy on theory , not so difficult to run on code , but now I want to step it up and add recursion so I can wrap my head around it better. The things is I am now finding it very difficult to do so. There is my code for:
- The node class
import java.util.ArrayList;
import java.util.List;
/**
* Implementation of a generic tree node containing the data and a list of children.
*
* #param <T> Generic type meant to implement reference types into the tree.
*/
public class Node<T> {
private T data;
private List<Node<T>> children;
/**
* Constructor that initializes the data and the list of children of the current node.
*
* #param data The value of the node.
*/
public Node(T data) {
this.data = data;
children = new ArrayList<>();
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public List<Node<T>> getChildren() {
return children;
}
public void setChildren(List<Node<T>> children) {
this.children = children;
}
}
-The tree class
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/** Implementation of a generic n-ary tree. */
public class Tree<T> {
private Node root;
private List<Node<T>> nodes;
/**
* Constructor that initializes the root node of the tree.
*
* #param data The value of the root node.
*/
public Tree(T data) {
root = new Node<>(data);
}
public Node getRoot() {
return root;
}
/**
* Method that implements the Level Order Traversal algorithm. It's a left to right traverse where
* each level of the tree is being printed out. First the root , then it's children and then each
* child's children etc.
*
* #param root The root node of a tree.
*/
public String levelOrderTraversal(Node root) {
StringBuilder result = new StringBuilder();
if (root == null) {
return "";
}
result.append("\n");
Queue<Node> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
int queueSize = q.size();
while (queueSize > 0) {
Node node = q.peek();
q.remove();
result.append(node.getData().toString()).append(" ");
for (int i = 0; i < node.getChildren().size(); i++) {
q.add((Node) node.getChildren().get(i));
}
queueSize--;
}
result.append("\n");
}
return result.toString();
}
/**
* This method serves to recursively move through and retrieve the nodes, so they can be printed
* out to the user.
*
* #param root The root node of the tree.
*/
private void walkThroughElements(Node root) {
if (root == null) {
return;
}
nodes.add(root);
for (Object node : root.getChildren()) {
walkThroughElements((Node) node);
}
}
/**
* Implementation of pre-order traversal of a generic tree. This traversal visit the root node
* first , prints it , then visits the whole left sub-tree (the list of every child node), prints
* every node and then traverses the right sub-tree , prints the nodes and ends the algorithm.
*
* #param root The root node of the tree.
* #return The nodes of the tree as a string.
*/
private String preOrderTraversal(Node<T> root) {
nodes = new ArrayList<>();
StringBuilder result = new StringBuilder();
walkThroughElements(root);
for (Node node : nodes) {
result.append(node.getData()).append(" ");
}
result.setLength(result.length() - 1);
return result.toString();
}
public String preOrderTraversal() {
return preOrderTraversal(root);
}
}
Is there an efficient way or does it even make sense to run this level order traversal method recursively?
This is the level order code after some changes
public String levelOrderTraversal(Node root) {
StringBuilder result = new StringBuilder();
if (root == null) {
return "";
}
result.append("\n");
Queue<Node> q = new LinkedList<>();
q.add(root);
collectNodes(root, root.getChildren());
result.append(root.getData().toString()).append(" ");
result.append("\n");
return result.toString();
}
It gives the error on the line where collectNodes is called.
This is what collectNodes() looks like.
private void collectNodes(Node<T> node, List<Node<T>> nodes) {
nodes.add(node);
for (Object child : node.getChildren()) {
collectNodes((Node) child, nodes);
}
}

You can solve those iteration problems using iteration (e.g. via a stack) or recursion. Let's use a method that gathers nodes much like your walkThroughElements():
Depth-first
Recursion
//add the node and then go deeper
void collect(Node node, Collection<Node> nodes) {
nodes.add(node);
for(Node child : node.getChildren()) {
collect(child, nodes);
}
}
Iteration
class Level {
final Node node;
Iterator<Node> childItr;
//constructor, setters, getters
}
void collect(Collection<Node> nodes) {
Stack<Level> levels = new Stack<>();
nodes.add(root);
levels.push(new Level(root, root.getChildren().iterator()));
while( !levels.isEmpty() ) {
Level currentLevel = levels.peek();
//remove the current level as it doesn't have any more children
if( !currentLevel.childItr.hasNext() ) {
levels.pop();
} else {
//get the next child and add it to the result
Node child = currentLevel.childItr.next();
nodes.add(child);
//go down to the child's level
levels.push(new Level(child, child.getChildren().iterator())
}
}
}
Breadth-first
Recursion
//add the children first (i.e. the entire level) and then go deeper
void collectChildren(Node node, Collection<Node> nodes) {
for(Node child : node.getChildren()) {
nodes.add(child);
collectChildren(child, nodes);
}
}
//special case: root node
void collect(Collection<Node> nodes) {
nodes.add(root);
collectChildren(root, nodes);
}
Iteration
void collect(Collection<Node> nodes) {
Queue<Node> nodesToProcess = new LinkedList<>();
nodesToProcess.add(root);
while( !nodesToProcess.isEmpty() ) {
Node node = nodesToProcess.poll();
nodes.add(node);
nodesToProcess.addAll(node.getChildren());
}
}
As you can see, recursion is easier on depth-first than breadth-first but easy to read anyway. Recursion will use the call stack to maintain state so it takes up (non-heap) memory and also has limits to its depth (depends on how much memory there is but the infamous StackOverflowException would tell you there's either a bug or the tree is too deep).
Iteration is easier with breadth first and requires additional constructs like a stack or a queue. It requires some heap memory for those constructs and may be faster due to some optimizations but in general I'd not bother about performance differences here as they should only manifest themselves for really large trees - and in that case recursion might hit the call stack limit already.

Using recursion typically will be slower than iteration and use more stack space as well.But Yes,this can also be solved using recursive way(DFS approach).
For your reference : https://leetcode.com/problems/binary-tree-level-order-traversal/discuss/33562/Java-1ms-DFS-recursive-solution-and-2ms-BFS-iterative-solution

The proper way is to do it in a lazy way
// assume not null Node::data (if so, wrap into Optional or similar)
static <T> Stream<T> levelOrderTraversal(Node<T> tree) {
final List<Node<T>> fifo = new ArrayList<>();
if(tree != null)
fifo.add(tree);
final Function<T, T> next = o -> {
if(fifo.isEmpty())
return null; // End Of Stream
Node<T> x = fifo.remove(0);
System.out.println("++++++ " + x.data);
if(x.children != null)
fifo.addAll(x.children);
return x.data;
};
return Stream.iterate(null, next::apply).skip(1).takeWhile(Objects::nonNull);
}
for example
++++++ foo
foo
++++++ bar1
bar1
++++++ bar2
bar2
++++++ par11
par11
++++++ par12
par12
++++++ par21
par21
++++++ par22
par22
++++++ subA
subA
++++++ subB
subB
where you only mantain the intermediate traversing level (not the whole tree).
For example, if you log every node expansion and filter the tree, not all nodes are logged
levelOrderTraversal(tree)
.takeWhile(x -> !x.equals("bar2"))
.forEach(System.out::println);
only expand the foo, bar1 and bar2 nodes
++++++ foo
foo
++++++ bar1
bar1
++++++ bar2

Related

Heterogeneous Binary Search Tree

I need to build a heterogeneous(Elements with different types) BST and be able to sort the elements but I do not know how to approach the problem.
I've got the binary tree code right here.
This is the node class
public class Node<T> {
T data;
Node<T> left;
Node<T> right;
Node(T data) {
this.data = data;
left = null;
right = null;
}
}
And this is the tree class.
public class Tree<T extends Comparable<T>> {
private Node<T> root;
StringBuilder result = new StringBuilder();
public Tree() {
root = null;
}
public Node<T> getRoot() {
return root;
}
/**
* Method that inserts nodes into the binary tree. If the tree is empty , a new root node is
* initialized.
*
* #param root A node object.
* #param dataBeingInserted The object to be inserted on the tree.
* #return The root node object
*/
private Node<T> insertNode(Node<T> root, T dataBeingInserted) {
if (root == null) {
root = new Node<>(dataBeingInserted);
return root;
}
if (dataBeingInserted.compareTo(root.data) < 0) {
root.left = insertNode(root.left, dataBeingInserted);
} else if (dataBeingInserted.compareTo(root.data) > 0) {
root.right = insertNode(root.right, dataBeingInserted);
}
return root;
}
public void insertNode(T dataBeingInserted) {
root = insertNode(root, dataBeingInserted);
}
/**
* Method that recursively searches for our element through the tree. If the value is present in
* the root node , or there aren't any nodes in the tree , the method returns the root node. If
* the value we're looking for is smaller than the root node's value , we search for our value in
* the left subtree , otherwise we search for it in the right subtree.
*
* #param root A node object.
* #param dataBeingSearched User's value.
* #return Recursive call of the method.
*/
private Node<T> searchTree(Node<T> root, T dataBeingSearched) {
if (root == null || dataBeingSearched.compareTo(root.data) == 0) {
return root;
}
if ((dataBeingSearched.compareTo(root.data) > 0)) {
return searchTree(root.left, dataBeingSearched);
}
return searchTree(root.right, dataBeingSearched);
}
public Node searchTree(T dataBeingSearched) {
return searchTree(root, dataBeingSearched);
}
/**
* An implementation of the In-order traversal. First the left subtree is visited and printed
* accordingly, then we visit and print the root and after that we visit and print the right
* subtree.
*
* #param root The root node object.
*/
private String inorderTraversal(Node root) {
if (root == null) {
return "";
}
inorderTraversal(root.left);
result.append(root.data).append(" ");
inorderTraversal(root.right);
return result.toString();
}
public void inorderTraversal() {
inorderTraversal(root);
}
}
The problem with my tree right now is that I'm getting ClassCastException whenever any element is different than the root , because there what happens is the root defines the type of the tree and I can't fix that.
P.S
Here is the snippet that gives me the error (I will post the whole main method for convenience.)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Scanner;
public class Main {
private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
private static final Scanner SCANNER = new Scanner(System.in);
public static void main(String[] args) {
Tree tree = new Tree<>();
tree.insertNode(50);
tree.insertNode("30");
tree.insertNode('b');
tree.insertNode(69.3);
tree.inorderTraversal();
LOGGER.info("{}", tree.result);
}
}
For example there the first insert is an Integer , after which I try to insert a String and right there it's giving me the ClassCastException , saying that String is incomparable with Integer.
I think, the comments thoroughly elaborated that comparing any two objects is not sensibly possible. However, you can still implement such a tree by decoupling the comparison from the tree logic.
On the contrary, every client will be hit with the exact same problem you are facing right now, but some clients might have specific solutions that work for them. We'll look into that later.
First of all, Java already defines a Comparator interface that goes along with Comparable.
package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
}
At the same time, let's rethink the tree interface. Basically, the requirements state that it should be able to accept just about any object, so it must have a method like
public void add(Object data);
At this point, there is no reason to use generics, since we can't actually make any restrictions. Even if there are other objects in the tree, it should still be able to accept any object.
Therefore, we could do something like
public class Tree {
private Comparator<Object> comparator;
private Node root;
public Tree(Comparator<Object> comparator) {
this.comparator = Objects.requireNonNull(comparator);
}
public void add(Object data) {
root = insertNode(root, data);
}
private void insertData(Node root, Object dataBeingInserted) {
// see below
}
}
with no major changes to the Node class except that it's not generic anymore as well. Now, when comparing two objects in the insertNode method, we simply consult the Comparator instance instead of doing the comparison ourselves.
if (comparator.compare(dataBeingInserted, root.data) < 0) {
root.left = insertNode(root.left, dataBeingInserted);
} else if (comparator.compare(dataBeingInserted, root.data) > 0) {
root.right = insertNode(root.right, dataBeingInserted);
}
A client can use this Tree implementation with a Comparator that s/he limits to the types s/he knows may occur.
public static void main(String[] args) {
Tree t = new Tree((o1, o2) -> {
if (o1 instanceof Number && o2 instanceof String) {
// numbers before strings
return -1;
}
if (o1 instanceof Integer && o2 instanceof Integer) {
return ((Integer) o1).compareTo((Integer) o2);
}
if (o1 instanceof String && o2 instanceof String) {
return ((String) o1).compareTo((String) o2);
}
throw new ClassCastException("incompatible types: " + o1.getClass().getCanonicalName()
+ ", " + o2.getClass().getCanonicalName());
});
t.add("Hello");
t.add(Integer.valueOf(1337));
}
As indicated by the ClassCastException, this solution is still not able to handle any possible type inherently. However, this Tree implementation can be used to handle every heterogeneous combination of types (as long as a client defines an appropriate Comparator).
I had a similar task in my java course. I used generics to define the tree. Then I created a tree of an interface, which is implemented by every node. The methods of the interface are then implemented in every node and this allowed me to compare and sort the objects. There is a simple example in this topic: simple heterogeneous k-ary tree in java (for creating network simulator)
I thought of the problem as of the products in a grocery store. Every product has id, brand, name, price but depending of the type of product they have to be cooled or have "best before" or need to be frozen or are not edible.

Depth first search in java - how to go back to parent node?

I'm trying to do a depth first search in Java recursively. At the moment, the code runs through my graph fine, but it never backtracks to find a route when they're are no more nodes to visit. I'm having a bit of a mental block honestly. What would be the best way to go back to the parent node?
Here is my code so far:
private final Map<Character, Node> mNodes;
private final List<Edge> mEdges;
public DepthFirstSearch(Graph graph){
mNodes = graph.getNodes();
mEdges = new ArrayList<>(graph.getEdges());
for(Node node : mNodes.values()){
node.setVisited(false);
}
}
public void depthFirstSearch(Node source){
source.setVisited(true);
List<Node> neighbours = source.getNeighbours(mEdges);
for(Node node : neighbours){
if(!node.isVisited()){
System.out.println(node.getName());
depthFirstSearch(node);
}
}
}
And the getNeighbour code:
public List<Node> getNeighbours(List<Edge> edges) {
List<Node> neighbours = new ArrayList<>();
for(Edge edge : edges){
if(edge.getFrom().equals(this)){
neighbours.add(edge.getTo());
}
}
return neighbours;
}
Added code for trying Jager's idea:
public void depthFirstSearch(Node source){
source.setVisited(true);
List<Edge> neighbours = source.getNeighbouringEdges(mEdges);
for(Edge edge : neighbours){
if(!edge.getTo().isVisited()){
System.out.println(edge.getTo().getName());
depthFirstSearch(edge.getTo());
}else{
depthFirstSearch(edge.getFrom());
}
}
}
Well, typically you have a root node that has children. Each child can have children of its own. So you would rather do:
public void depthFirstSearch(Node source)
{
for(Node node : source.getChildren())
{
System.out.println(node.getName());
depthFirstSearch(node);
// and right here you get your back tracking implicitly:
System.out.println("back at " + node.getName());
}
}
Note that I do not have a necessity for a member visited...
Edit:
Now that you provided your data structure, let me propose another approach:
class Node
{
// all that you have so far...
private char mId;
private List<Node> mChildren = new ArrayList<Node>();
public char getId()
{
return mId;
}
public List<Node> getChildren()
{
return Collections.unmodifiableList(children);
}
// appropriate methods to add new children
}
The id replaces the key of your map. Then you simply have a root Node mRoot to start with somewhere. This is the typical way to implement trees.
You might want to go up from a child node directly. Then you'd additionally need a private Node parent; in the node class (immediately being set to this when adding a child to the private list and set to null, when being removed). You won't use this for backtracking, though, so the depth first search above remains unchanged.
Guessing: you are "getting" the neighbors for mEdges which seems to be a field of the surrounding class.
Most likely, you should ask each node for its own edges upon visiting it.

Implementation of DFS using iterative approach in java

I have seen a lot of implementations of DFS using a boolean variable named visited, which I don't wish to use in my code. While considering a scene where we have a Node class that holds the reference to left and right nodes corresponding to its children and data which can be any Object, can this method be applicable to Binary Trees to calculate dfs ? I have a scenario where I don't have a adjacency list or matrix.
Is the following code a good implementation of DFS ? Is the time complexity of the code O(n) ?
public void dfsForTree(BSTNode root) {
Stack<BSTNode> s = new Stack<BSTNode>();
BSTNode node;
if (root == null) {
return;
}
s.push(root);
while (!s.isEmpty()) {
node = s.pop();
System.out.println(node.getData());
if (node != null) {
if (node.getRight() != null) {
s.push(node.getRight);
}
if (node.getLeft != null) {
s.push(node.getLeft);
}
}
}
}
BSTNode class implementation:
public class BSTNode {
private BSTNode left;
private BSTNode right;
private int data;
/* Constructor */
public BSTNode(int n) {
left = null;
right = null;
data = n;
}
/* Function to set left node */
public void setLeft(BSTNode n) {
left = n;
}
/* Function to set right node */
public void setRight(BSTNode n) {
right = n;
}
/* Function to get left node */
public BSTNode getLeft() {
return left;
}
/* Function to get right node */
public BSTNode getRight() {
return right;
}
/* Function to set data to node */
public void setData(int d) {
data = d;
}
/* Function to get data from node */
public int getData() {
return data;
}
A sure tell of an iterative tree walk is it requires an "up" link on a node (or saves them) to be able to backtrack. You do just this - only saving not "up" links but directly next links to go after backtracking. On the other hand, there are no interdependencies between steps. See Is this function recursive even though it doesn't call itself? for how to distinguish iterative and disguised recursive.
Also see Iterative tree walking for an overview of the algorithms.
Now, for computational complexity. The principle can be found at Big O, how do you calculate/approximate it?.
You do:
process every node
exactly once
push & pop nodes from the stack
each node is also pushed and popped exactly once
So, indeed, it's O(N).

Inserting an element to a binary tree

This is my implementation of binary Node class:
public class BinaryNode{
int element;
BinaryNode left;
BinaryNode right;
BinaryNode(int theElement,BinaryNode lt,BinaryNode rt){
element=theElement;
left=lt;
right=rt;
}
BinaryNode(int theElement){
this(theElement,null,null);
}
}
Here's my insert method in binaryTree class
public class BinaryTree {
private BinaryNode root;
public BinaryTree(){
root= null;
}
BinaryTree(int nodeValue){
root=new BinaryNode(nodeValue);
}
public void insert(BinaryNode node,int x){
if(node==null){
node=new BinaryNode(x);
}
else if(node.element<x){
insert(node.left,x);
}
else if (node.element>x){
insert(node.right,x);
}
else
System.out.println("Duplicates not allowed");
}
I have two questions.
1) how can I insert elements to this BinaryTree class and thereby create a tree.
public static void main (String args[]){
BinaryTree t=new BinaryTree();
t.insert(t.root,5);
}
But after inserting 5 how can I call on insert method to add integers like 10,12,78,...
2) Also when I looked up at some code for inserting to binary trees I found this code .
/**
Inserts the given data into the binary tree.
Uses a recursive helper.
*/
public void insert(int data) {
root = insert(root, data);
}
/**
Recursive insert -- given a node pointer, recur down and
insert the given data into the tree. Returns the new
node pointer (the standard way to communicate
a changed pointer back to the caller).
*/
private Node insert(Node node, int data) {
if (node==null) {
node = new Node(data);
}
else {
if (data <= node.data) {
node.left = insert(node.left, data);
}
else {
node.right = insert(node.right, data);
}
}
return(node); // in any case, return the new pointer to the caller
}
The code looks similar to mine, but why use a helper method insert() as well?What's the purpose of it?
Can someone please solve help me to understand this
Inserting an element in a binary tree should require only the tree and the element as input. The tree itself should determine which node should be updated. This is achieved by means of a recursive function which starts from root: this is the helper function, which acts on a node.
The first problem is that you won't be able to access t.root directly because it's private. You either need a getter
public BinaryNode getRoot() {
return this.root;
}
or make root public
The helper method is used, so the new root of the BinaryTree can be determined. And because the root should not be returned to the caller. But since it's easier to insert something into a binary tree recursivley the private method is used to do that.
You would use the methods like this:
public static void main(String[] args) {
BinaryTree t = new BinaryTree(5); //Create a new tree with one item
t.insert(12); // Assuming that you used the implementation with the helper method
t.insert(3); //
t.insert(t.getRoot(),12); // Assuming you used your implementation
t.insert(t.getRoot(),3); //
}

How to deep copy a Binary Tree?

I would like using my own Node class to implement tree structure in Java. But I'm confused how to do a deep copy to copy a tree.
My Node class would be like this:
public class Node{
private String value;
private Node leftChild;
private Node rightChild;
....
I'm new to recursion, so is there any code I can study? Thank you!
try
class Node {
private String value;
private Node left;
private Node right;
public Node(String value, Node left, Node right) {
this.value = value;
...
}
Node copy() {
Node left = null;
Node right = null;
if (this.left != null) {
left = this.left.copy();
}
if (this.right != null) {
right = this.right.copy();
}
return new Node(value, left, right);
}
}
Doing it recursively using pre-order traversal.
public static Node CopyTheTree(Node root)
{
if (root == null)
{
return null;
}
Node newNode = new Node(null, null, root.Value);
newNode.Left= CopyTheTree(root.Left);
newNode.Right= CopyTheTree(root.Right);
return newNode;
}
You can use something like this. It will go though the old tree depth first wise and create a copy of it.
private Tree getCopyOfTree(oldTree) {
Tree newTree = new Tree();
newTree.setRootNode(new Node());
copy(oldTree.getRootNode(), newTree.getRootNode())
return newTree;
}
private void copy(Node oldNode, Node newNode) {
if (oldNode.getLeftChild != null) {
newNode.setLeftChild(new Node(oldNode.getLeftChild()));
copy(oldNode.getLeftChild, newNode.getLeftChild());
}
if (oldNode.getRightChild != null) {
newNode.setRightChild(new Node(oldNode.getRightChild()));
copy(oldNode.getRightChild, newNode.getRightChild());
}
}
I like Evgeniy Dorofeev's answer above, but sometimes you might not be able to add a method to the type Node as you might not own it. In that case(this is in c#):
public static TreeNode CopyTree(TreeNode originalTreeNode)
{
if (originalTreeNode == null)
{
return null;
}
// copy current node's data
var copiedNode = new TreeNode(originalTreeNode.Data);
// copy current node's children
foreach (var childNode in originalTreeNode.Children)
{
copiedNode.Children.Add(CopyTree(childNode));
}
return copiedNode;
}
Not sure but try something with post order traversal of your tree and creating a new node for each node you traverse. You might require stack for storing the nodes you created to make left and right child links.
public static TreeNode copy( TreeNode source )
{
if( source == null )
return null;
else
return new TreeNode( source.getInfo( ), copy( source.getLeft( ) ), copy( source.getRight( ) ) );
}
/Sure. Sorry for the delay. Anyway... any recursive method has a base case, and one or more recursive cases. In this instance, the first line is obvious... if the argument to the parameter 'source' is null (as it eventually evaluates to in order to end the method's operation), it will return null; if not, the recursive case is initiated. In this case, you're returning the entire copied tree once the recursion is complete.
The 'new' operator is used, indicating the instantiation of a TreeNode with each visit to the various nodes of the tree during the traversal, occurring through recursive calls to 'copy', whose arguments become references to the left and right TreeNodes (if there are any). Once source becomes null in each argument, the base case is initiated, releasing the recursion stack back to the original call to 'copy', which is a copy of the root of the original tree./
Node copy(Node node)
{
if(node==null) return node;
Node node1 =new Node(node.data);
node1.left=copy(node.left);
node1.right=copy(node.right);
return node1;
}

Categories

Resources