I wrote these method for my program and i felt that it is hard to read as there are too many loops, is there any other alternative to this code to make it look cleaner and easier to read
public static void printRoutingTable(Map <Node, List<Edge>> adj, Node Root)
{
for (Node thisNode : adj.keySet())
{
Node currentNode = thisNode;
String nextHop;
if(currentNode.getParent() != null){
do{
if(currentNode.getParent() != Root){
currentNode = currentNode.getParent();
nextHop = currentNode.getAddr();
}
else{
nextHop = currentNode.getAddr() ;
}
}
while(currentNode.getParent() != Root);
}
else
{
nextHop = ""+currentNode.getAddr();
}
nextHop = nextHop.trim();
}
}
I've not tried, but this should be a functional and recursive version of your code.
String getNextAddr(Node node, StringBuilder sb, Node root) {
sb.add(node.getAddr());
if (node.getParent() != null && node.getParent() != root) {
return getNextAddr(node.getParent(), sb);
}
return sb.toString();
}
String nextHopList =
adj.keySet()
.stream()
.map(k -> getNextAddr(k, new StringBuilder(), Root))
.collect(Collectors.toList())
It's difficult to tell what your code is trying to achieve. At the moment it's not actually doing anything because the nextHop variable is local and nothing seems to be accumulated in the loop. I'm assuming you intend to join the strings your are generating.
there's no point passing in a map if you aren't going to use it. Better to pass a collection (or, better, Stream) of nodes.
generally the root node is the only one with a null parent. So it's likely you also don't need to pass in a reference to the root node.
if parent is optional I suggest you return Optional<Node> from getParent rather than Node.
an easy way to make the code easier to read is to break the parts into separate methods that are named after exactly what they do.
So taking these suggestions into account, something like the following:
String getRoutingTable(Stream<Node> nodes) {
return nodes
.flatMap(this::getRoutingForNode)
.map(Node::getAddr)
.collect(joining(";"));
}
private Stream<Node> getRoutingForNode(Node node) {
Stream.Builder<Node> pathToRoot = Stream.builder();
for (Node c = node; c.getParent().isPresent(); c = node.getParent().get()) {
pathToRoot.accept(c);
}
return pathToRoot.build();
}
Note that in Java 9 the getRoutingForNode will become much more readable as you will be able to dispense with the Builder:
return Stream.iterate(node,
n -> node.getParent().isPresent(),
n -> n.getParent().get());
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 am trying to write a code to convert a binary tree to a lists of nodes with same depth. If a tree has depth d, then d lists will be created. The logic is to do in-order traversal and add the currently traversed node to the list of appropriate depth.
public void treeToListofNodesByLevel(Node<T> n,int depth, ArrayList<LinkedList<Node<T>>> treeList){
if(n.right != null){
inOrderWithHeight(n.right, depth + 1);
}
if(treeList.size() >= depth){
treeList.add(depth, new LinkedList<Node<T>>() );
}
treeList.get(depth).add(n);
if(n.left != null){
inOrderWithHeight(n.left, depth + 1);
}
}
and then calling:
ArrayList<LinkedList<Node<T>>> result = new ArrayList<LinkedList<Node<T>>>();
treeToListofNodesByLevel(root, 0, result);
Will this work ? Are there any corner cases I am not handling ?
Also, right now I am passing the List of List to be returned by the method because I can not think of a way to initialize it in the method and returning it at then end while also maintaining the recursive structure. Is there a better way to do this ?
You have the general concept pretty much perfect. It will work, and should handle all cases.
However, you have a few errors in the details:
Your check for when to add a new list has the comparison in the wrong direction. It should be if (treeList.size() <= depth).
Each call to inOrderWithHeight() (which you haven't provided any code of) should be a recursive call to treeToListofNodesByLevel(). Keep the first two arguments as they are, and just pass the treeList for the third.
This one's more a style issue, but parameter types should generally be declared as the highest level type that satisfies what you actually need. There is no need here to specify ArrayList or LinkedList, any List will do. Change the treeList parameter's type to List<List<Node<T>>>.
For the matter of initializing the List inside the method while also using recursion, that's the sort of thing that implementation helper methods are for. Take the current body of treeToListofNodesByLevel and move it into a private method (with the recursive calls changed so the private method calls itself), let's call it treeToListofNodesByLevelHelper. Then change the current public method to this:
public List<List<Node<T>>> treeToListofNodesByLevel(Node<T> node) {
List<List<Node<T>>> result = new ArrayList<>();
treeToListofNodesByLevelHelper(node, 0, result);
return result;
}
I cannot understand what the method "inOrderWithHeight" is doing. What I do for this question (not optimized) is to traverse like BFS using two queues and for each iteration adding the nodes of that depth to the list of that iteration (each iteration is traversing one depth of the tree). Here is my code to do that for a binary tree as you supposed in your answer:
Queue<Node<T>> queue1 = new LinkedList<Node<T>>() ;
Queue<Node<T>> queue2 = new LinkedList<Node<T>>() ;
public void treeToListofNodesByLevel(Node<T> root, ArrayList<LinkedList<Node<T>>> treeList) {
if (root == null)
return;
int curr_depth = 0;
queue1.add(root);
while(!queue1.isEmpty()){
treeList.add(curr_depth, new LinkedList<Node<T>>());
while(!queue1.isEmpty()){
Node<T> node = queue1.remove();
treeList.get(curr_depth).add(node);
if(node.left != null) queue2.add(node.left);
if(node.right != null) queue2.add(node.right);
}
curr_depth++;
while(!queue2.isEmpty()){
Node<T> node = queue2.remove();
queue1.add(node);
}
}
}
I wrote this on the fly without syntax checking and may have compiler errors. But hopefully you get the idea.
Why you just use the same function the code will be more beautifull :
public void treeToListofNodesByLevel(BinaryTree node, int currentDepth, List<List<BinaryTree>> result){
// Check if the list for the currentDepth is created
if(result.get(currentDepth) != null){
result.add(currentDepth, new ArrayList<BinaryTree>())
}
// Add the current node to the list
result.get(currentDepth).add(node);
// Recursive the left node
if(node.left != null){
treeToListofNodesByLevel(node.left, currentDepth+1, result);
}
// Recursive the right node
if(node.right != null){
treeToListofNodesByLevel(node.right, currentDepth+1, result);
}
}
In your main function :
List<List<BinaryTree>> result = new ArrayList<>();
BinaryTree root = new BinaryTree();
treeToListofNodesByLevel(root, 0, result);
I've been tasked with finding and returning a particular node from a general tree given by the string targetName. Take a look at my implementation below:
public GeneralTreeNode findNode(String targetName) {
if (this.name.equals(targetName)) {
return this;
} else {
for (GeneralTreeNode child : this.children) {
return child.findNode(targetName);
}
}
// no node containing the string could be found
return null;
}
The only problem is that this too often seems to incorrectly return null when in fact a node does exist. It's as if the last line, return null, is too greedy.
Chucking a few breakpoints on this and watching it shows it only seems to go down to the lowest depth until a node has no children, in which case it simply returns null.
Can anyone offer suggestions on how to improve this?
Change your code to this:
public GeneralTreeNode findNode(String targetName) {
if (this.name.equals(targetName)) {
return this;
} else {
for (GeneralTreeNode child : this.children) {
GeneralTreeNode childResult = child.findNode(targetName);
if (childResult != null) {
return childResult; // only return if you really found something
}
}
}
// no node containing the string could be found
return null;
}
You only want to return the result from the child search if it really found something.
The readability of the code disappears if you implement in this way. Tree-traversal would be better implemented in an helper class and you pass the ROOT element with the target_name together.
If you return null in this way, it is something like node is null actually it is not. On the other hand, when you use "doer" or "processor" method/function, it can return true saying "I cannot find anything".
Still, your code seems ok. I just rewrite it.
static Node search(Node node, String nodeName) {
if (node.getName().equals(nodeName)) return node;
List<Node> children = node.getChildren();
foreach(Node child : children) {
Node resultChild = search(child, nodeName);
if (resutlChild != null) return resultChild;
}
return null;
}
For example, in the function below, which adds a node to BST, I have used only implicit references.
I could have declared explicitly a variable TreenNode node = .., at start of function and used it where appropriate. Now, I am not aware if it is opinion based or not. Sincerely is there any pros or or con of using OPTION1 over OPTION2
OPTION1:
public void add(int item) {
if (root == null) {
root = new TreeNode(null, item, null);
return;
}
TreeNode node = root;
while (true) {
if (item < node.item) {
if (node.left == null) {
node.left = new TreeNode(null, item, null);
break;
}
node = node.left;
} else {
if (node.right == null) {
node.right = new TreeNode(null, item, null);
break;
}
node = node.right;
}
}
}
OPTION 2:
public void add(int item) {
TreeNode nodeNew = new TreeNode(null, item, null); // explicit
if (root == null) {
root = nodeNew;
return;
}
TreeNode node = root;
while (true) {
if (item < node.item) {
if (node.left == null) {
node.left = nodeNew;
break;
}
node = node.left;
} else {
if (node.right == null) {
node.right = nodeNew;
break;
}
node = node.right;
}
}
}
Option 1 is more optimizied as it involves less steps.
Option 2 means you create a variable holding a reference to only use it to assign - it only may look better for some people. In option 1 you skip the temporary reference and make the assignment and object creation directly.
At the end of the day however, there isn't another difference.
Also, in option 2 it is better to move your declaration of nodeNew below the return.
Why initialize something if you won't use it.
if (root == null) {
root = node;
return;
}
TreeNode nodeNew = new TreeNode(null, item, null); // explicit
First of all, I think the line root = node; in option 2, you probably intend it to be: root = nodeNew;, do you?
There is a potential benefit I think, in that everywhere that nodeNew is referenced in option2, it's within a conditional, so it may never be used. In this case, option1 has the advantage of only instantiating a new TreeNode object when it's needed.
In this particular case though, it looks like each call to this add method will always need to create a new TreeNode -- if not in the initial condition, then at some iteration of the while loop; so in this case there isn't really an efficiency benefit that I can see in that respect.
One aspect of this that might be worth thinking about (and talking to other people who may work on your code also), is the maintainability of it. I see a potential advantage and a potential disadvantage to option1 in this case. Maybe these situations don't apply to the specific example that you've given, but may to others that this question applies to:
Potential advantage:
If this is a long section of code, it's always clear at all of the points where a new TreeNode is being created, that it is in fact a TreeNode object that's being created (and not, say, some derivative), and what parameters were passed to its constructor.
Potential disadvantage:
If it will never be subclassed, and all instantiations in this method will be given the exact same parameters, then option2 has the benefit of having one place where a change needs to be made (change one of the parameters for example).
I tried to convert a List from 3{1{,2{,}},5{4{,},6{,}}}
to a Binary Tree like this
3
1 5
2 4 6
I thought it would be easier to use recursion but I get stuck.
public void ListToTree (ArrayList al) {
Iterator it = al.iterator();
// n is the Tree's root
BSTnode n = new BSTnode(it.next());
recurse(al,it,n);
}
void recurse (ArrayList al, Iterator it, BSTnode n) {
if(!it.hasNext()) return;
Object element = it.next();
if(element=="{"){
recurse(al,it,n.left());
return;
} else if (element==",") {
recurse(al,it,n.right());
return;
} else if (element =="}") {
}
}
I don't know how to proceed and was wondering if it's the right track. Please give me some hints how to solve it. Moreover, I realize I often get stuck on recursive questions. Is it because I always want to break it down? Should I just think top-down and double-check if it's correct? Thanks in advance !
Firstly: are you bound to that terrible list representation? You can easily build a BST based on the BST rules with this code:
void insert(Node n, int value) {
if(n == null) {
n = new Node(value);
} else if(value < n.value) {
if(n.left == null) {
n.left = new Node(value);
return;
}
insert(n.left, value);
} else if(value > n.value) {
if(n.right == null) {
n.right = new Node(value);
return;
}
insert(n.right, value);
}
}
You really don't have to pass the iterator. Just use the values from the list. Also it is usually unadvised to use implementation types in method signatures. (i.e. ArrayList -> List).
Another big mistake here is that you don't use == for value comparison, that is for reference comparison. Use equals instead, but you should downcast the Object after an instanceof test e.g.:
if( element instanceof String) {
String seperator = (String)element;
if("{".equals(separator))
//do sth...
Btw the thing you are missing from the code is the actual insertion and the backwards navigation.
After you found the right subtree by navigating with the {-s and ,-s, check whether the element is an Integer then set it as a value for the current node. Backwards navigation should be in the } branch by either returning one level from the recusion and some tricks or calling the method on the parent of the actual node.
But I don't suggest you to follow this direction, it is much easier to just use the values from the list and the simple insertion method.