I am trying to iterate through a recursive object but Java has no support for this from what I know.
For example, given the object Item:
public class Item {
Long uuid;
List<Item> children;
}
With a for loop I could iterate through children but since children will contain more children which will contain more children and so on, there's no way to automatically determine the depth and loop based on that depth.
Is there a way to iterate through recursive objects?
If the tree is very deep, use a breath-first search as suggested by Eran. If the tree is very wide, use a depth-first search which could look something like:
class ItemVisitor {
public void accept(Item item) {
// Do something
for (Item i : item.getChildren()) {
this.accept(i);
}
}
}
EDIT:
For a breath-first search, use a queue and append all the children of the current node onto it.
public void visitTree(Item head) {
Queue<Item> queue = new PriorityQueue<Item>();
while (queue.size() > 0) {
Item curr = queue.poll();
// Do something
for (Item i : curr.getChildren())
queue.add(i);
}
}
If you don't have cycles within the parent-child tree you can use a simple recursive function to determine the number of descendants:
public class Item {
...
public int getDescendantCount() {
int count = 0;
if (children != null) {
count += children.size();
for (Item child : children)
count += child.getDescendantCount();
}
return count;
}
}
Something similar to this?
void read(Item item) {
if (item == null) {
//do something with the uuid ?
return;
} else {
for (Item i : item.children) {
read(i);
}
}
}
I don't know what the exact goal of the function is, but you can always loop recursively through children.
For example
public void loopChildren(List<Item> items) {
for (Item i : items) {
System.out.println(i.uuid);
loopChildren(i.children);
}
}
It just keep looping until the end of the list. If a child has no children List should be empty so it terminates for that iteration.
Hope this helps.
If you can store depth as a separate data item and enforce it via class design/encapsulation, you're good there.
What you're proposing is a node of some kind of tree of indeterminate depth. You can implement any normal depth-first or breadth-first search method; look it up in any standard data structures and algorithms textbook/web reference and implement in Java. The solution Eran posted while I was typing is a standard depth-first search if you use a Stack (last-in-first-out or LIFO queue), or a breadth-first search if you use a FIFO queue. These are nice and clean methods, but not the simplest.
The most naïve method would be a simple recursive function for a depth-first search:
public void recurseIntoChildren(Item item) {
if(item.children.size() == 0) {
// you are now at a leaf node: do something
}
for(Item child : item.children) {
recurseIntoChildren(child);
}
}
This form assumes you want to do something at leaf nodes. If you are searching for something, you can have recurseIntoChildren() return a special value when you find what you want so you can break out of all the rest of the recursive loops (let it return null or some other value to indicate the loop should continue). If you want to take other action, up to you to work this to your needs.
This is not the most efficient method (unless the compiler optimises tail recursion into a simple loop).
Related
I have a BinaryTree and I want to get all nodes of a specific level. Order does not matter. I want to try to do this with recursion . My method looks like this:
public List<T> getNodesOnLevel(int i){
int recursionTool = i
//to do
recursionTool-=1
}
I tried to while(recursionTool != 0){ method.... and then recursionTool -1}
But I ended up getting all nodes until the wanted level.
My Node looks like this:
class Node<T>{
T val;
Node<T> left;
Node<T> right;
Node(T v){
val = v;
left = null;
right = null;
}
It is possible to implement this as a pure functional algorithm by concatenating the lists returned by recursive calls. Unfortunately, that is rather inefficient in Java because all retrieved values are copied by list creation or concatenation once at each recursion level.
If you are willing to use mutation, here is a solution that avoids the copying (assuming that this is a Node<T>):
private void getNodesOnLevel(int level, List<T> list) {
if (node == null) return;
if (level == 0) {
list.add(this.val);
} else {
this.left.getNodesOnLevel(level - 1, list);
this.right.getNodesOnLevel(level - 1, list);
}
}
The above method needs to be called with an empty (mutable) list as the 2nd argument, so we need another method:
public List<T> getNodesOnLevel(int level) {
List<T> list = new ArrayList<>();
this.getNodesOnLevel(level, list);
return list;
}
(In complexity terms, the pure functional solution is O(LN) where L is the level and N is the number of nodes at that level. My solution is O(N). Each value in the list will be copied twice on average, due to the way that ArrayList.append implements list resizing. The resizing could be avoided by creating the list with a capacity of 2level.)
This may help you. I had used this method to print nodes but you can change it.
public void printGivenLevel(TNode root, int level) {
if (root == null)
return;
if (level == 1 && root.getValue() != null) {
// here, add root.getValue() to list
} else if (level > 1) {
printGivenLevel(root.getLeft(), level - 1);
printGivenLevel(root.getRight(), level - 1);
}
}
I have a Node class. It has a children ArrayList. That list consists of Nodes as well. And said nodes have children lists, and so on.
Basically, it's a tree in somewhat not so convenient form. Let's say I want to delete someNode from it. So how to clear all of the child lists recursively?
I have a hasChildren() method, which returns if specified node has children, I think it has to help me, but can't figure out how yet. I've also got getChildren() method which returns list of children.
Here's some of my code, but it is wrong all over the place.
public void removeChild()
{
while(hasChildren())
{
getChildren();
removeChild();
}
children.clear();
}
You can implement a Queue which you can use to put every Node's children and then pop from it to remove them.
Something like this.
Queue<Node> queue = new LinkedList<>();
queue.add(node); //node to remove
while(!queue.isEmpty()) {
Node currentNode = queue.pop();
for(Node n : currentNode.getChildren) {
queue.add(n);
{
currentNode.getChildren.clear();
}
UPDATE: To do it recursively you could implement something like this (just be aware of stack size in java).
public void removeChildren(Node node)
{
for(Node n : node.getChildren()) {
removeChildren(n);
}
node.getChildren().clear();
}
In my opinion you just need to clear the children (as shown below) and the Garbage collector will automatically free rest of the objects.
public void removeChild()
{
if(hasChildren())
{
children.clear();
}
}
So I just wrote code for insertion of nodes in binary tree (NOT BST).
I noticed that every time the recursive insert returns a 'node', it is assigned to the initial node.
Does this mean, that the memory reference of root of this tree would change on the completion of each insert?
public void add(int data)
{
root=add(root,data);
}
public static BinaryNode add(BinaryNode node, int data) {
if(node==null)
{
node=new BinaryNode(data);
}
else {
///IF not 1st element, flow enters this part
if(node.left==null && node.right==null)
{
node.left=add(node.right,data);
}
else if (node.right == null) {
node.right=add(node.right, data);
} else {
node.left=add(node.left, data);
}
}
return node;
}
Within add the only time you change node is if the tree at that point is empty, so the answer is no except for the first insert.
However, note that you add a new level to the tree only on the left (first if condition) so the "tree" you build is highly unbalanced to the left. This isn't really a "tree", it's more like a strange linked list. Also, since you don't maintain any particular sequence it can't be better than a simple unordered list for searches.
Is there a way to recursively traverse a tree and return an array that is scoped to that recursive method?
So I recently answered someone else's question on this topic. That question can be found here: SO Question. My solution uses an array outside of the scope of the recursion, and therefore the method cannot (or at least probably should not) return the array. However, is there a way to write a recursive method for traversing trees such that it returns an array? Even writing an initial method that calls the recursive one would be fine, but I can't think of a good way to do this.
Here's the code that I suggested before:
private List nodeValues = new ArrayList();
public void traversePreRecursive(BinarySearchTreeNode node)
{
if (node != null)
{
nodeValues.add(node.getValue());
traversePreRecursive(node.getLeft());
traversePreRecursive(node.getRight());
}
}
As you can see the ArrayList is outside of the scope of the recursion - And therefore returning it doesn't make a lot of sense. Is there a better way to do this?
public static List traversePreRecursive(Node node) {
if (node == null) return new ArrayList();
List nodeValues = new ArrayList();
nodeValues.add(node.getValue());
nodeValues.addAll(traversePreRecursive(node.getLeft()));
nodeValues.addAll(traversePreRecursive(node.getRight()));
return nodeValues;
}
There is an alternative, but it involves two passes over the tree. You would only employ this alternative if the array operations in my first answer were giving you grief. This approach starts by providing an index for each of the nodes (the index() method) -- basically working out which element of the array a node should occupy before we actually create the array. This also gives me a count of nodes (size). I then allocate an array (list) big enough to hold all the nodes and pass it into a method (addToList) that copies the node-references into the previously identified element in the array.
public static List<Node> getNodes(Node a) {
int size = index(a, 0);
List<Node> list = new ArrayList<Node>(size);
addToList(a, list);
return list;
}
private static int index(Node node, int index) {
if (node == null) return index;
node.setIndex(index);
int iLeft = index(node.getLeft(), index++);
int iRight = index(node.getRight(), iLeft++);
return iRight + 1;
}
private static void addToList(Node node, List<Node> list) {
if(node == null) return;
list.add(node.getIndex(), node);
addToList(node.getLeft(), list);
addToList(node.getRight(), list);
}
In c you can have static function variables,(Ie, adding a value to a list in one iteration of a function means that that value will be in the list in the next iteration--if the list is static) but using them isn't the best (most optimal) solution for the problem you are suggesting. So, I think you are searching for static variables, but this isn't an appropriate case to use them.
I am trying to change my recursive insert method of the BST into non-recursive( maybe While loop)
The reason for this changing because I want to see if it is possible.
Here is the code of insertion:
public void insert(String value)
{
//The node is stored in the root
root = insert(value,root);
}
private Character insert(String value,Character current)
{
if(current == null)
{
//Add the root if the tree empty
current = new Character(value);
}
else
//If the value that we want to insert < root value, then keep going to left till
//it's empty then inserted at left end. Done by recursion
if(value.compareTo(current.getElement())<=-1)
{
current.setLeft(insert(value,current.getLeft()));
}
else
//If the value that we want to insert > root value, then keep going to right till
//it's empty then inserted at right end. Done by recursion
if(value.compareTo(current.getElement())>=1)
{
current.setRight(insert(value,current.getRight()));
}
else
{
//Else, the number we want to insert in already in the tree
System.out.println("Duplicate numbers inserted" + current.getElement());
}
//returning the node tree so that we store it in the root
return current;
}
Could I change this code into non recursive ?
Cheers
Yes, but you need to alter the data structure a little bit to make it works.
The node has to know its left child and right child.
The algorithm looks like this:
current = root;
while(current != null){
if(value.compareTo(current.getElement())<=-1)
{
current = current.left_child;
}else if(value.compareTo(current.getElement())>=1){
current = current.right_child;
}else{
// Duplication
}
}
Actually there are some good examples before, you may want to check those out first:
Write a non-recursive traversal of a Binary Search Tree using constant space and O(n) run time
Nonrecursive/Iterative Binary Search Tree in C (Homework)
Yes, you could define your insert function non-recursively.
However, to do this, your insert function will have to define in-order traversal iterator for BST, which is recursively defined.
I believe there is a way to define in-order traversal non-recursively, but depending on implementation this can be very inefficient.
BST itself is basically recursively defined, and it is always efficient to define your insert function recursively. (I could write some pseudo-code if you really need it, but I think it is kind of meaningless and I do not know about the implementation detail of your in-order traversal iterator)
Please don't forget to select this as an answer :-)
Insert using while loop
public Node insert(Node root,int n) {
while (true) {
if (root.data>n) {
if (root.left==null) {
root.left= new Node(n);
return (root.left);
}
root=root.left;
}
else if (root.data<n) {
if (root.right == null) {
root.right= new Node(n);
}
}
}
}