I need to traverse a binary tree, skipping the children of any node for which a condition is met.
This implements a tree-guided clustering approach; the leaves of a subtree are considered a cluster when they collectively meet the condition.
It seems like the place to start would be pre-order traversal, but I'm not sure how to modify the algorithm to skip all the children of the current node.
Update
In addition to the two (correct) answers below, one can use the following Java libraries:
MyArch TreeIter - Generic (with adapter class) tree traversal, with child skipping and dynamic maximum traversal depth
Phylosoft Forester - Tree implementation with getAllExternalDescendants and a Newick-to-XML converter
If by skipping all the children you mean not just direct descendants but their entire subtrees, you can do the following:
public void traverse(Node n){
if (n==null)
return;
doSomethingWith(n);
if (!conditionIsMet(n)){
traverse(n.left);
traverse(n.right);
}
}
the first part is easy:
class Tree {
Tree(int data) {
this.data = data;
}
Tree left, right;
Object object;
int data;
}
public class Main {
static void myPreorder(Tree tree) {
if (tree == null) return;
if (tree.data > 2) {
System.out.println("skipping " + tree.data);
return;
}
System.out.println("visiting " + tree.data);
myPreorder(tree.left);
myPreorder(tree.right);
}
public static void main(String[] args) {
Tree root = new Tree(1);
root.left = new Tree(2);
root.right = new Tree(3);
root.right.left = new Tree(4);
root.right.right = new Tree(5);
myPreorder(root);
}
}
the second part: " ... the leaves of a subtree are considered a cluster when they collectively meet the condition. ..." is hard. you would need to examine all of the leaves of a node to see that they met the skip condition.
Related
This question also applies to various linked lists methods as well. So, when I have a method:
public void insert(String key)
{
if(top == null)
{
top = new Node(key);
}else {
Node newNode = new Node(key);
Node rover = top;
Node prev = top;
boolean wentLeft = true;
while(rover != null)
{
if (rover.getName().compareTo(key) < 0)
{
prev = rover;
rover = rover.getRight();
wentLeft = false;
}else {
wentLeft = true;
prev = rover;
rover = rover.getLeft();
}
}
if(wentLeft == true)
{
prev.setLeft(newNode);
}else {
prev.setRight(newNode);
}
}
nElems++;
}
How is the top of the Binary Search Tree and its children updated despite not being directly set anywhere in the method?
I know this likely has something to do with shallow copying and that like rover/prev are still referencing top in memory but I still don't really get it.
Even though I feel like I understand Linked Lists and Binary Search Trees on a conceptual level I don't feel comfortable moving forward with them without understanding this.
There are no copies being made. When you assign prev = top, that only creates another reference to the same object as top, not a copy.
The code works because nodes are inserted one by one.
When prev.setLeft/setRight is called, prev is already in the tree because it was inserted before. So prev is already in the tree, i. e. the parent of prev is top, or the parent of the parent of prev, you get the idea. Thus, when new_node becomes child of prev, it becomes part of the tree.
This is what makes linked lists and trees so useful. When you insert an element, you only have to make one connection.
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);
}
}
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.
I am trying to make a (spanning) tree that comes naturally from traversing a graph (undirected and connected) using Breadth First Search, but I am having difficulties modifying the algorithm such that it makes a tree. I am using Java.
Here is my BFS algorithm.
public void traverse(Node node){
Queue queue= new Queue();
node.visited= true;
//Maybe do something here?
queue.enqueue(node);
while (!queue.isEmpty()){
Node r= queue.dequeue();
for (int i= 0; i < r.childen.size(); i++){
Node s= (Node)r.childen.get(i);
if (s.visited == false){
//And do something here?
s.visited= true;
queue.enqueue(s);
}
}
}
}
My graph data structure is simply this (note it's undirected and connected) :
public class Graph {
Node mainNode; ...
And the tree data structure is also simply this:
public class Tree {
Node root; ...
My Node is like this:
public class Node<T> {
T data;
boolean visited= false;
ArrayList<Node> childen= new ArrayList<Node>();
...
I think my trouble comes from the fact that I can't simply add some Node node from the graph directly to my tree (because this node would have all its children already). Instead, I have to make a new Node(node.data) so that the added node in the tree doesn't point to all the adjacent nodes that the same node would point in the graph.
So my question: how do I make a (spanning) tree out of graph while traversing the said graph using Breadth First Search?
I'm going to operate off the assumption that the graph is both undirected and connected. That being said, I think you're on the right track, but you're going to need a few more things. First, I highly encourage you to keep your search state and node implementation separate - in other words, it's not a great idea to store a private member variable Node.visible just to aid your search.
You can avoid this by maintaining some extra state inside your search method, and use a recursive private helper method to hide that state from callers of your public traverse() method. You will need to properly implement equals and hashCode in your Node class to do this.
Also - if you are wanting to create a completely separate Tree with different nodes, you'll want to essentially create new, empty instances of each Node in the Graph and first populate them with their counterpart's data, then build the tree using the cloned nodes. That said, here's some code to get you going (I haven't tested this, but it should give you an idea of what to do):
/**
* This facade method traverses just the root of the new tree. All recursion is
* passed to the "traverseHelper(3)" recursive method.
*/
public Tree<T> traverse(Graph<T> g){
if(g == null || g.mainNode == null) return null;
Node<T> node = g.mainNode;
Node<T> clone = new Node<T>(node.data); //this is the root of our new Tree
Set<Node<T>> searched = new HashSet<Node<T>>(); //accumulates searched nodes
searched.add(node);
traverseHelper(node,clone,searched);
return new Tree<T>(clone);
}
/**
* Recursively performs BFS on all the children of the specified node and its
* corresponding cloned instance.
*
* Assumes that "node" has been added to "searched" and that
* "searched.contains(node)" AND "searched.contains(clone)" will return true by
* the time this method is called.
*/
private void traverseHelper(Node<T> node, Node<T> clone, Set<Node<T>> searched){
if(node.children == null) return;
Map<Node<T>,Node<T>> toRecurseOn = new HashMap<Node<T>,Node<T>>();
//This is the Breadth-First part - builds the next leaves in the tree:
for(Node<T> child : node.children){
if(child == null || searched.contains(child)) continue;
Node<T> childClone = new Node<T>(child.data); //create leaf in the tree
clone.children.add(childClone); //builds the current level in the tree
childClone.children.add(clone); //maintains undirected-ness of the tree
toRecurseOn.put(child,childClone); //lets us BFS later
}
//This is the Search part - builds the subtrees:
Iterator<Node<T>> i = toRecurseOn.keySet().iterator();
while(i.hasNext()){
Node<T> child = i.next();
Node<T> childClone = toRecurseOn.get(child);
i.remove(); //Saves a little memory throughout the recursion
traverseHelper(child,childClone,searched);
}
}
I found a simple answer to my question. Instead of building a tree, I remove edges which lead to already visited nodes (this information we get for free as part of the BFS algorithm). Below is my implementation (it might be modified if one doesn't want to destroy the initial graph structure).
public static Tree BFS(Node node){
Queue queue= new Queue();
node.visited= true;
queue.enqueue(node);
while (!queue.isEmpty()){
Node r= queue.dequeue();
for (int i= 0; i < r.childen.size(); i++){
Node s= (Node)r.childen.get(i);
if (s.visited == false){
s.visited= true;
queue.enqueue(s);
}
else{
//Remove edge here
r.childen.remove(i);
i--;
}
}
}
Tree tree= new Tree(node);
return tree;
}
EDIT. The following is an implementation which doesn't destroy the initial graph structure by keeping a separate queue.
public static Tree BFS(Graph G, Node node){
Queue queue= new Queue();
Queue treeQueue= new Queue();
ArrayList<Node> tempV= new ArrayList<Node>();
tempV.add(node);
queue.enqueue(node);
Node root= new Node(node.data);
treeQueue.enqueue(root);
while (!queue.isEmpty()){
Node r= queue.dequeue();
Node t= treeQueue.dequeue();
for (int i= 0; i < r.childen.size(); i++){
Node s= (Node)r.childen.get(i);
if (tempV.indexOf(s) < 0){
tempV.add(s);
Node child= new Node(s.data);
t.childen.add(child);
queue.enqueue(s);
treeQueue.enqueue(child);
}
}
}
Tree tree= new Tree(root);
return tree;
}
I am attempting to create a binary tree from an input of 0's and 1's. For example if the input is 11010010 then the tree that is outputted would have 1 as the root. 2 would be the left child of 1 and 4 would be the right child. 2 would have a right child and it would be 3. That is the end of the tree. As the tree is traversed in preorder, the numbers 1-n (n being the number of 1's in the input) are assigned to the nodes that are visited. A 1 means that the root has children. For example the first 1 means that the root is visited and a 1 is placed as the root. The second 1 means that the root has a left child and a 2 is placed there. The 0 after that means it does not have a left child. The next 1 means that it does have a right child and the 3 is placed there, etc. I am confused on how this tree is created. I understand traversing a tree after it has been created but not how to create a tree by traversing it. Any help would be appreciated.
package tree;
import java.io.*;
public class BinaryTree<ArrayList> implements Serializable
{
private static final long serialVersionUID = 1L;
protected static class Node<ArrayList> implements Serializable
{
private static final long serialVersionUID = 1L;
protected int data;
protected Node<ArrayList> left;
protected Node<ArrayList> right;
public Node(int data)
{
this.data = data;
left = null;
right = null;
}
public boolean isLeft()
{
return (left == null);
}
}
protected Node<ArrayList> root;;
public BinaryTree(int x)
{
Node<ArrayList> node = new Node<ArrayList>(x);
this.root = node;
}
public boolean isLeft()
{
return(root.left == null);
}
public void addLeft(int m, BinaryTree.Node<ArrayList> node)
{
root = new Node<ArrayList>(m);
node.left = root;
}
public void preorder(Node<ArrayList> temp)
{
if (temp!=null)
{
System.out.println(temp.data);
preorder(temp.left);
preorder(temp.right);
}
else
return;
}
}
It sounds like you're constructing a tree in a default, breadth-first manner, assigning values to each node based off of what the string says.
If it helps, first turn the string into an ArrayList<int> of values to put in nodes - For example, 11010010 would become {1, 2, 4, 7}, the indices of each set 1 in the string.
Now, we have to construct the tree - but we'll always construct the tree in the exact same way, called breadth first because you fill shallow levels completely before going deep. We make a node, then tell it 'make your left node, then make your right node, then tell your left node to do this, then tell your right node to do this'. (This is as opposed to depth first, where you make your left node, tell your left node to make nodes, then make your right node and tell your right node to make nodes)
So you'd have a recursive method something like this pseudocode:
void continueTree(ArrayList<int> numbers)
{
if (numbers.count() == 0) return;
this.left = new Node(numbers.get(0));
numbers.remove(0);
if (numbers.count() == 0) return;
this.right = new Node(numbers.get(0));
numbers.remove(0);
this.left.continueTree(numbers);
this.right.continueTree(numbers);
}