I'm learning how to traverse a tree by levels. The method I do should take the level of tree number and print back a nodes at the current level.
I watched this tutorial - "Print nodes at given Level", but still can't figure out how is recursion working in this concrete sample.
So please, help me to understand.
// Java program for Inserting a node
class GFG1 {
static class node {
int key;
node left, right;
}
static node newNode(int item)
{
node temp = new node();
temp.key = item;
temp.left = temp.right = null;
return temp;
}
// Function to insert a new node
static node insert(node node, int key)
{
// If the tree is empty, return a new node
if (node == null)
return newNode(key);
// Otherwise, recur down the tree
if (key < node.key) {
node.left = insert(node.left, key);
}
else if (key > node.key) {
node.right = insert(node.right, key);
}
return node;
}
static void printGivenLevel(node root, int level)
{
if (root == null)
return;
if (level == 1) {
System.out.print(" " + root.key);
}
else if (level > 1) {
printGivenLevel(root.left, level - 1);
printGivenLevel(root.right, level - 1);
}
}
public static void main(String[] args)
{
node root = null;
root = insert(root, 50);insert(root, 30);insert(root, 20);insert(root, 40);insert(root, 70);insert(root, 60);insert(root, 80);
printGivenLevel(root,2);
}
}
The method of traversal by levels is printGivenLevel:
So why it requires to write level-1 in printGivenLevel(root.left, level - 1) and not works with 'level +1', for example?
How do we come to the base condition, for example on the 3-th or 2-nd tier?
The tree looks like
50
30 70
20 40 60 80
level is an ambiguous term here, in the printGivenLevel it starts from the top "level", which is technically level 1, and we recurse down until we reach our desired "level".
Actual level "level" inside printGivenLevel(root, level)
1 50 3
2 30 70 2
3 20 40 60 80 1
Let's see how printGivenLevel(root, 2) executes, renaming printGivenLevel as print:
1. print(root, 2) -> print(root.left(30), 1) and print(root.right(70), 1)
2. print(root(30), 1) -> we are at "level 1", print the value 30.
3. print(root(70), 1) -> we are at "level 1", print the value 70.
The base condition always reaches when "level" becomes equal to 1, we start counting down from the top level, and when we reach our desired level, the "level" count becomes 1 and we print the value of the node.
So why it requires to write level-1 in printGivenLevel(root.left, level - 1) and not works with 'level +1', for example? How do we come to the base condition, for example on the 3-th or 2-nd tier?
If level is always increased, it'll keep on increasing and won't reach level 1, no value would be printed and it'd result in stackoverflow.
Related
I'm looking to return the nth largest data value in the subtree rooted at this node in a BST that can have duplicate values.
Right now I have this but it doesn't seem to work
static int get(BSTNode node, int n) {
if ( node == null || n < 0)
return 0;
if ( n == 0)
return node.data;
get(node.right, n--);
get(node.left, n--);
return 0;
}
This is my Node class
private int data; // key
private int dataCount; // no. of keys with equal value stored at this node
private int treeSize; // no. of keys stored in the subtree rooted at this node
private BSTNode leftChild;
private BSTNode rightChild;
I have implemented an iterative solution.
Idea
The basic idea is to always go as far to the right as possible as the largest values will be there as long as a node has not yet been counted against n and save all values along the path we go in a stack.
If we can't go to the right anymore and we've not counted this node against n already we've found the largest node in the tree that we have not accounted for yet. So in that case we can account for that value by getting the node from the stack, decrementing n and adding that node to the set of nodes we've already accounted for. To find the next largest value we'll have to check if the current node has a left subtree and if it has, we need to continue there. If it does not we need to go back to our parent node which we do by getting the next value from the stack. This parent node will then automatically be the next largest value.
Here an illustration of those two scenarios possible when being at the largest value that has not been accounted for.
We're at the largest node that has not been accounted for and it has no left node, so we need to go back to the parent (using the stack) which will be the next largest node.
Parent
/ \
/ \
x largest
Alternatively: there is a left subtree, we need to examine first.
Parent
/ \
/ \
x largest
/
/
left subtree
/ \
/ \
Implementation
/**
* Finds the n-th largest key in a given subtree.
* #param root root node to start from
* #param n n-th largest key to get, n =< 1 will result in the largest key being returned
* #return returns n-th larges value, if n <= 1 return largest value
*/
public Node findNthLargestKey(Node root, int n){
if(root == null) return null;
if(n < 1) n = 1;
// early out: if you know how many nodes you have in the tree return if n is bigger than that
// based on number of nodes compared to n some assumptions could be made to speed up algorithm
// e.g. n == number of nodes -> get to left-most node and return it
// if n is close to number of nodes also probably start in left branch instead of all the way on the right side at the biggest node
var stack = new Stack<Node>();
// remember nodes that have been visited and have been counted against n
var done = new HashSet<Integer>();
// start at root node
stack.add(root);
// continue as long as the stack is not empty, if it is n was to big and the n-th largest value could not be found
while (!stack.empty()){
// pop next value from the stack (will be root in first iteration)
current = stack.pop();
// always try to go as far to the right as possible to get the biggest value that has not yet been counted against n
while (current != null && !done.contains(current.getKey())){
stack.add(current);
current = current.getRight();
}
// if we are here we've found the biggest value that has not yet been counted against n
var prev = stack.pop();
// if we have found the nth biggest value return
if(--n == 0){
return prev;
}
// otherwise mark this node as done and counted against n
done.add(prev.getKey());
// if node has a left successor, visit it first as this node has no right successors that have not been counted against n already
if(prev.getLeft() != null) stack.add(prev.getLeft());
}
// n-th largest value was not found (n was too big)
return null;
}
My Node looks like this with getters and setters defined of course. But the implementation will also work for your node, as the number of nodes with same value are irrelevant to find the n-th largest node. And even if they were not , the same algorithm would work but then you would need to decrement by the number of nodes with same value and the condition would need to be adjusted to n <= 0 to return.
public class Node {
private int key;
private Node right;
private Node left;
private Object anyData;
public Node(int key) {
this(key, null);
}
public Node(int key, Object anyData) {
this.key = key;
this.anyData = anyData;
this.left = null;
this.right = null;
}
}
Test
I've tested my implementation against random trees and the results have always been correct. This Test class however only checks results for the root node to be able to test the method for every node in the tree. I've additionally also run some test where n > number of nodes in tree which always has to return null for not found and for smaller subtrees.
public class Test {
public static void main(String[] args){
// values to insert into the tree
int[] curVals = fillArrayRand(20, 1, 200);
// Create tree
BinarySearchTree tree = new BinarySearchTree();
System.out.println("Tree has been created.");
// fill tree
for (var cur: curVals) {
tree.insertIter(new Node(cur));
}
// print values in order of insertion, first value will be the root value
System.out.println("Tree was filled with the following values: %s".formatted(Arrays.toString(curVals)));
// print tree in using inorder traversal
tree.printRec(Traversal.INORDER);
var sorted = Arrays.stream(curVals).sorted().distinct().toArray();
// always start at root node; which is the first node that gets inserted
// find() returns a given node by key
var startNode = tree.find(curVals[0]);
// now loop over sorted values (sorted in ascending order -> nth largest is at position n - i in the sorted array)
for (int i = 0; i < sorted.length; i++) {
var result = tree.findNthLargestKey(startNode, sorted.length - i);
// if key in i-th position of sorted array is the same as the key of result => success
// if result is null, the node was not found (should not happen here as sorted.length - i is never > sorted.length)
System.out.printf("#%d largest value:\t%d (expected)\t-\t%s (result)\t", sorted.length - i, sorted[i], result == null ? "not found": result.getKey());
if (result != null && sorted[i] == result.getKey()) {
System.out.println("SUCCESS");
} else System.out.println("FAILED");
}
}
public static int[] fillArrayRand(int size, int randStart, int randEnd){
int[] randArray = new int[size];
for(int i = 0; i < size; i++){
randArray[i] = (int)( (randEnd - randStart) * Math.random() + randStart);
}
return randArray;
}
}
Expected output
Tree has been created.
Tree was filled with the following values: [148, 65, 18, 168, 8, 148, 194, 186, 114, 22, 102, 51, 123, 169, 68, 118, 37, 18, 26, 18]
((((n,8,n),18,(n,22,(((n,26,n),37,n),51,n))),65,(((n,68,n),102,n),114,((n,118,n),123,n))),148,(n,168,(((n,169,n),186,n),194,n)))
#17 largest value: 8 (expected) - 8 (result) SUCCESS
#16 largest value: 18 (expected) - 18 (result) SUCCESS
#15 largest value: 22 (expected) - 22 (result) SUCCESS
#14 largest value: 26 (expected) - 26 (result) SUCCESS
#13 largest value: 37 (expected) - 37 (result) SUCCESS
#12 largest value: 51 (expected) - 51 (result) SUCCESS
#11 largest value: 65 (expected) - 65 (result) SUCCESS
#10 largest value: 68 (expected) - 68 (result) SUCCESS
#9 largest value: 102 (expected) - 102 (result) SUCCESS
#8 largest value: 114 (expected) - 114 (result) SUCCESS
#7 largest value: 118 (expected) - 118 (result) SUCCESS
#6 largest value: 123 (expected) - 123 (result) SUCCESS
#5 largest value: 148 (expected) - 148 (result) SUCCESS
#4 largest value: 168 (expected) - 168 (result) SUCCESS
#3 largest value: 169 (expected) - 169 (result) SUCCESS
#2 largest value: 186 (expected) - 186 (result) SUCCESS
#1 largest value: 194 (expected) - 194 (result) SUCCESS
Note: the output of the line with all the parenthesis is the output of the inorder traversal where (left node, parent, right node) and n means null for i. e. no node. The first node that gets inserted is the root node, so it's best to start to read the output from there.
Correctness
I should be possible using a loop invariant and induction to proof the algorithm is correct and produces the expected result for every correct binary search tree and input. The loop variant (informally) would be after an iteration i of the outer while loop, we have found the i-th largest node in the tree for 1 <= i <= n. I have not done that here, but using the idea that should be straightforward.
Effectiveness
I have not done a complexity analysis but it is obvious that the best case e.g. root node is largest value and we want the largest value the complexity is O(1). In worst case it will be O(n) no matter which node we search for. The algorithm could certainly be improved for some inputs i. e. if we have n close to the number of nodes in the tree, meaning we are searching for a small value. In that case it will be faster to start from the left-most node which is the smallest and search for the (number of nodes - n)-th smallest value. If you were to implement something like this you could certainly greatly improve the average case runtime.
When dealing with recursive data structures, you can often expect some recursive code to work on them. This case is not an exception either, just the recursive parts will need some dirtiness.
Let's use the 3-element BSTs for designing, labeled with insertion-order:
123 132 213,231 312 321
1 1 2 3 3
\ \ / \ / /
2 3 1 3 1 2
\ / \ /
3 2 2 1
Finding the largest element is easy:
just go to the right as long as you can
You will bump into 3, no matter what level it is.
Finding the second largest element is the revealing part:
going to the right as long as it's possible still seems to be a good start
then we look at where we are:
if it's a leaf node, return to the parent, and that will be the one (123,213,231 cases)
if there's a left-child, check that one, but as the 312 case in particular shows, "checking" the left-child actually means step 1, so again go to the right as long as it's possible.
The recursion is somewhat found, and these really are the steps we need for larger cases too. It's also somewhat seen that when we are going to the right, the "nth-ness" of the next number we will check doesn't change. It starts changing only when we are stepping to the left (132,312,321), or returning to a previous level (123,213,231).
The dark part is that we have to track this counter somehow. We found the answer when it reaches 0 (so starting this algorithm with n=0 finds the largest element), and after that (when n goes negative) it will just return the value it got from recursion.
First here is a JavaScript PoC, using a bit dirty hacks, like if a member variable doesn't exist at all yet, it still can be checked (the if(this.left) things), and the counter is a one-element array (so it can be modified across the recursive calls), the method is called as root.nthback([i]), where the [i] is an array literal. Also, the method doesn't bother returning anything when the element doesn't exist, that produces the two undefineds at the end of the test output. These shortcuts will be addressed in the Java variant at the end of this post.
The example input was just taken from the other answer, on top of their availability, they have some repeats too.
const init = [148, 65, 18, 168, 8, 148, 194, 186, 114, 22, 102, 51, 123, 169, 68, 118, 37, 18, 26, 18];
class Node {
nthback(n) {
if (this.right) {
let res = this.right.nthback(n);
if (n[0] < 0)
return res;
}
if (n[0]-- === 0)
return this.value;
if (this.left) {
let res = this.left.nthback(n);
if (n[0] < 0)
return res;
}
}
constructor() {
this.value = NaN;
}
add(value) {
if (isNaN(this.value)) {
this.value = value;
} else if (value < this.value) {
if (!this.left)
this.left = new Node;
this.left.add(value);
} else {
if (!this.right)
this.right = new Node;
this.right.add(value);
}
}
walk() {
let result = "";
if (this.left)
result = this.left.walk() + ",";
result += this.value;
if (this.right)
result += "," + this.right.walk();
return result;
}
}
const root = new Node;
for (const value of init)
root.add(value);
console.log(root.walk());
for (let i = 0; i < 22; i++)
console.log(root.nthback([i]));
So the actual magic is quite short and also symmetric:
nthback(n) {
if (this.right) { // 1
const res = this.right.nthback(n); // 2
if (n[0] < 0) // 3
return res;
}
if (n[0]-- === 0) // 4
return this.value;
if (this.left) { // 5
const res = this.left.nthback(n);
if (n[0] < 0)
return res;
}
}
If there is something on the right (1), it has to be checked (2), and if the counter is negative afterwards (3), the result we got back is the actual result of the entire call, so we pass it back.
If we are still in the method, (4) is where we check if the counter is exactly 0, because then this node has the actual result, which we can return. It's worth to remember that the n[0]-- part decrements the counter regardless of the outcome of the comparison. So if n[0] was 0 initially, it will become -1 and we return this.value;. If it was something else, it just gets decremented.
(5) does the (1)-(2)-(3) part for the left branch. And the hidden JavaScript thing is that we don't have to return anything. But the (4)-(5) parts will change when using your complete structure anyway.
Adding subtree-size allows early return if the incoming counter is simply larger than the size of the entire subtree: we just decrement the counter by the size, and return, the element is somewhere else. And this also means that when we don't return, the result is in the subtree, so we check the possible right branch, then ourselves, and if we are still inside the method, we don't even have to check if we have a left branch, because we do have it for sure, and it does contain the result, also for sure. So (5) will simply become a direct return this.left.nthback(n);. Which is quite a simplification.
Tracking multiplicity affects (4): instead of checking for 0, we will have to check if the counter is less than the multiplicity, and also, instead of decrementing the counter by 1, we have to subtract the actual multiplicity from it.
const init = [148, 65, 18, 168, 8, 148, 194, 186, 114, 22, 102, 51, 123, 169, 68, 118, 37, 18, 26, 18];
class Node {
nthback(n) {
if (this.size <= n[0]) {
n[0] -= this.size;
return 0;
}
if (this.right) {
let res = this.right.nthback(n);
if (n[0] < 0)
return res;
}
if (n[0] < this.count) {
n[0] -= this.count;
return this.value;
}
n[0] -= this.count;
return this.left.nthback(n);
}
constructor() {
this.value = NaN;
this.size = 0;
}
add(value) {
this.size++;
if (isNaN(this.value)) {
this.value = value;
this.count = 1;
} else if (value === this.value) {
this.count++;
} else if (value < this.value) {
if (!this.left)
this.left = new Node;
this.left.add(value);
} else {
if (!this.right)
this.right = new Node;
this.right.add(value);
}
}
walk() {
let result = "";
if (this.left)
result = this.left.walk() + ",";
result += this.value;
if (this.count > 1)
result += "x" + this.count;
result += "(" + this.size + ")";
if (this.right)
result += "," + this.right.walk();
return result;
}
}
const root = new Node;
for (const value of init)
root.add(value);
console.log(root.walk());
for (let i = 0; i < 22; i++)
console.log(root.nthback([i]));
So the final JavaScript variant could look like this:
nthback(n) {
if (this.size <= n[0]) { // 1
n[0] -= this.size;
return 0;
}
if (this.right) { // 2
let res = this.right.nthback(n);
if (n[0] < 0)
return res;
}
if (n[0] < this.count) { // 3
n[0] -= this.count; // 4
return this.value;
}
n[0] -= this.count; // 4
return this.left.nthback(n); // 5
}
Subtree-skipping happens in (1), by comparing subtree-size, and the target count we can immediately tell if the result is in this subtree or somewhere else. While JavaScript would allow a simple return; here, a 0 is produced instead, as it seems to be desired in the question.
The next step (2) is unchanged from the previous variant, looks exactly same, does exactly same.
(3) had to be taken apart. While the post-decrement operator was helpful previously, there's no post--= operator, so it happens for both outcomes of the comparison (4). Also, we don't compare === 0 as before, but we compare < this.count instead. By the way, we could have done that in the previous case too if we really wanted to, there this.count was always 1, so < 1 could have done the thing (the counter is never negative at this point, that can only happen in the left/right returns). In fact if we really-really wanted to, we could do the subtraction prior to the comparison, and instead of the current 0<=n fact and n<count check, we could shift the comparison downwards, knowing that now -count<=n and checking for n<0.
(5) became the one-liner as promised. If we reach this point, the result is unconditionally inside the left-branch, which unconditionally exists.
Making it Java
The simplest part is the array-trick: there could be a public method to call, accepting an actual number, and then it could wrap it into an array, and call a private method doing the actual job. Also changed the variable names to the ones you have:
public int nthback(int n) {
return nthback(new int[] { n });
}
private int nthback(int[] n) {
if (treeSize <= n[0]) {
n[0] -= treeSize;
return 0;
}
if (rightChild != null) {
int res = rightChild.nthback(n);
if (n[0] < 0)
return res;
}
if (n[0] < dataCount) {
n[0] -= dataCount;
return data;
}
n[0] -= dataCount;
return leftChild.nthback(n);
}
As you have private members, these methods have to reside in the same source file, and then they could just reside directly inside class BSTNode anyway.
Here in my binary tree data structure:
//Every node has value and index
class Node<T> {
Node<T> left,right;
int index;
T value;
Node(T value, int index){
this.index = index;
this.value = value;
}
}
class Tree<T> {
int depth;
Node<T> root;
//Create an empty binary tree
private static Tree<Object> empty = new Tree<>();
#SuppressWarnings("unchecked")
public static <K> Tree<K> empty(){
return (Tree<K>) Tree.empty;
}
//creating a binary tree by taking depth as input
public static <K> Tree<K> depth(int deepest){
if(deepest > 0) {
Tree<K> tree = Tree.empty();
tree.root = new Node<>(null,0);
tree.addLevel(tree.root, 0, deepest, 0);
return tree;
}
else {
throw new Error();
}
}
private void addLevel(Node<T> node, int depth, int deepest,int index){
if (depth == deepest - 1) {
return;
} else {
node.left = new Node<>(node.value,index*2+1);
node.right = new Node<>(node.value,index*2+2);
addLevel(node.left,depth+1,deepest, index*2+1);
addLevel(node.right,depth+1,deepest,index*2+2);
}
}
public void getAllElem(Node<T> node, List<HashMap<T,Integer>> list) {
if (node == null) {
return;
}
else {
HashMap<T, Integer> pairs = new HashMap<T, Integer>();
getAllElem(node.left,list);
pairs.put(node.value, node.index);
list.add(pairs);
getAllElem(node.right,list);
}}
In that case, I want to create a method getParent(int index), when the user pass the index number to the method, it will return the value of the parent node.
For example, when the inputted index = 3, it will get the value of node(index = 1).
But I don't have any clue about how to do that, any advice? Thanks!
A naive algorithm would be to from the parent node check the leaf indices and return the parent value as soon as one has found the desired leaf index, namely:
T getParent(int index, Node<T> node){
if(node == null)
return null;
else if(node.left != null && node.left.index == index || node.right != null && node.right.index == index)
return node.value;
else{
T value = getParent(index, node.left);
return (value != null) ? value : getParent(index, node.right);
}
}
This algorithm would have a time-complexity in the worst-case scenario of N, so pretty inefficient. One could, however, try to improve it to O(log2N), if one would search only on the right or left leaf depending on the current parent index. For that one needs to find an expression that will let one knows which leaf to continue the search.
The most efficient algorithm for this problem takes O(1). Since for a given node with index n, their leaves will be at the indices 2n + 1 and 2n + 2, so you can make a small table and try to figure out the formula (that based on the leaf index returns the parent index):
index | parent
0 | no parent
1 | 0
2 | 0
3 | 1
4 | 1
5 | 2
6 | 2
7 | 3
8 | 3
9 | 4
10 | 4
Based on that table, one can infer that code-wise, one can obtain the parent index using the formula (i-1)/2 with i > 0, and i begin the index of the leaf that one is looking for:
i = 2 -> (2-1)/2 = 0 (the value will be rounded down)
i = 3 -> (3-1)/2 = 1
i = 4 -> (4-1)/2 = 1 (the value will be rounded down)
....
i = 10 -> (10-1)/2 = 4 (the value will be rounded down)
so the code would be something as straightforward as :
int getParentIndex(int index){
return (index == 0) ? -1 : (index - 1) / 2;
}
However, for this algorithm to work, you need to have an additional structure that stores the nodes by indices, so that you can access their values in O(1). For instance, using an ArrayList:
private static List<Node<T>> nodes = new ArrayList<>();
When you add a node to your tree, you also added to that list. Then with the getParentIndex method you can access that index in the list, and retrieve the Node value.
This is the typical approach used on a Binary Heap.
I am trying to calculate a sum of each branch of a binary tree without using recursion. I'm trying to use a stack and can't figure out how to fix my code to get the right sums.
public static List<Integer> branchSums(BinaryTree root) {
LinkedList<BinaryTree> toVisit = new LinkedList<>();
BinaryTree current = root;
List<Integer> sums = new ArrayList<>();
int sum = 0;
while (current != null || !toVisit.isEmpty()) {
while (current != null) {
sum += current.value;
toVisit.push(current);
current = current.left;
}
current = toVisit.pop();
// if found leaf add sum to results and decrement sum by current node
if (current.left == null && current.right == null) {
sums.add(sum);
sum -= current.value;
}
current = current.right;
}
return sums;
}
Example input:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ /
8 9 10
Example output [15, 16, 18, 10, 11]
Issue with your code is you are not keeping track of the node which
has been last popped from your stack.
Here is the updated code:
public static List<Integer> caculateSum(BinaryTree root) {
List<Integer> sums = new ArrayList<>();
int sum=0;
BinaryTree current = root, popped=null;
Stack<BinaryTree> s = new Stack<BinaryTree>();
while(current!=null ) {
//checking if last node popped from stack is not equal to left or right node of current node
if(popped==null||((current.left!=null && !current.left.equals(popped)) && (current.right!=null && !current.right.equals(popped)))) {
while(current != null) {
sum+=current.value;
s.push(current);
current = current.left;
}
}
current=s.peek();
if(current.right == null) {
//if current node is leaf node
if(current.left == null) {
sums.add(sum);
}
sum-=current.value;
popped = current;
s.pop();
} else if(current.right!=null && current.right.equals(popped)){
//if current node both left and right nodes have been processed
sum-=current.value;
popped = current;
s.pop();
}else {
//if current node right part is not processed
sum+=current.right.value;
s.push(current.right);
}
if(s.isEmpty()) {
break;
}
current=s.peek();
}
return sums;
}
Will explain this by taking an example. Suppose we have given binary tree
1,2,9,3,7,null,8,5
Here in above code apart from old variables a new variable popped is used which keeps track of last element which is popped out from stack.
So, following are the major steps :
Starting from current node first we are checking if current node left is not equal to popped (if it is equal it means that current node left part is already processed so we don't need to process it again). Same we are checking if current node right node is not equal to popped node (if it is equal it means we have already processed right node of current node which indirectly means left node is also processed).
Now for the top node of stack which is current node we check :
If its right node is null If it is true it means either current
node is leaf node or it is an already processed node whose right
node is null (like in our example node with value of 3). If it is
leaf we add it in our sums list. Also, for both cases we remove
this top node and subtract its value from current sum value
(This thing has been done in above code as well) .Along with this we
will keep track of popped element from stack in popped variable.
If its right is not null but its right node is equal to popped
node This happens when in last pass of while loop we had processed
this right node. This means for top node of stack both left and
right node have been processed and hence we pop this node and keep
track of it in popped variable.
Else we push the right node of top element of stack in stack.
At the end for above example , sums variable will store result as [11, 10, 18]
I attempted this for fun and was surprised I didn't see any actual solutions. The following is in Kotlin but can easily be transcribed into Java. The trick was to add state to the Node itself to mark it as consumed before you popped it, otherwise there was no value there to check when going down another branch.
This might be useful in super rare cases to prevent stack overflow? This will still run in O(N) but takes more space with the stacks, and will visit a node twice, once to traverse and once to pop.
open class BinaryTree(value: Int) {
var value = value
var left: BinaryTree? = null
var right: BinaryTree? = null
var consumed: Boolean = false
}
fun branchSums(root: BinaryTree): List<Int> {
var sumList = ArrayList<Int>()
var nodeStack = ArrayList<BinaryTree>()
var valueStack = ArrayList<Int>()
nodeStack.add(root)
while(!nodeStack.isEmpty()) {
val node = nodeStack.get(nodeStack.size-1)
if (node.consumed) {
valueStack.removeAt(valueStack.size - 1)
nodeStack.removeAt(nodeStack.size - 1)
continue
}
valueStack.add(node.value)
if (node.right == null && node.left == null) {
var sum = 0
for (value in valueStack) {
sum += value
}
sumList.add(sum)
}
if (node.right != null) {
nodeStack.add(node.right!!)
}
if (node.left != null) {
nodeStack.add(node.left!!)
}
node.consumed = true
}
return sumList
}
You can have this method:
public static int getBranchSum(Node root){
Queue<Node> q = new LinkedList<>();
q.add(root);
int sum=0;
while (!q.isEmpty()) {
Node curNode = q.poll();
sum+=curNode.data;
if(curNode.left==null || curNode.right==null)
curNode.visited=true;
if(curNode.left != null && curNode.left.visited)
curNode.visited=true;
if(curNode.left!=null && !curNode.left.visited)
q.add(curNode.left);
else if(curNode.right!=null && !curNode.right.visited)
q.add(curNode.right);
}
root.visited=false;
return sum;
}
Then call it below in a while loop as long as the output is not equal the root data.
boolean flag=true;
List<Integer> list = new ArrayList<>();
while(flag){
int result =getBranchSum(root);
if(result == root.data)
flag=false;
else
list.add(result);
}
System.out.println(list);
However the above the working only if we have a visited boolean in the node:
class Node{
Node left,right;
int data;
boolean visited = false;
Node(int data){
this.data=data;
left=right=null;
}
Branch sum without recursion
def branchSums(root):
cs=0
stack=[{"node":root,"cs":cs}]
sums=[]
while(len(stack)>0):
node_info=stack.pop()
node,cs=node_info["node"],node_info["cs"]
if node is None:
continue
cs=cs+node.value
if node.left is None and node.right is None:
sums.append(cs)
print(sums)
stack.append({"node":node.right,"cs":cs})
stack.append({"node":node.left,"cs":cs})
return sums
I want to convert a sorted integer array into a binary search tree. I have posted my code below. What I cannot picture is how the recursion actually works with the for loop as inserting.
So if my array is [1,3,4, 5,8,10] I make 4, which is the mid of the array, become the root of my BST, then loop from the start of array and insert to the tree with root just created. My question is why the order of result inserted is not as the sorted given array?
public TreeNode sortedArrayToBST(int[] A) {
if (A == null || A.length == 0){
return null;
}
TreeNode root = new TreeNode(findMid(A));
for (int i = 0; i < A.length; ++i){
insert(root, A[i]);
}
return root;
}
private int findMid(int[] A){
int left = 0;
int right = A.length -1;
int mid = A[left + (right - left)/2];
return mid;
}
private void insert (TreeNode root, int val){
if (root == null || root.val == val){
return;
}
if (val < root.val){
TreeNode left = new TreeNode(val);
root.left = left;
}
if (val > root.val){
TreeNode right = new TreeNode(val);
root.right = right;
}
insert(root.left,val);
insert(root.right,val);
}
You have a couple problems with your recursive insert method. First off, everytime the val is not equal to the root's value, you create a new node. This is faulty because by doing this, you create multiple nodes and set the root's child at each step of the recursion to these new nodes, which is redundant. Let's go through your method for each node.
Adding 4
4
Adding 1
4
/
1
Adding 3
4
/
3
At this point, we can pinpoint the error. Why was 4's left child replaced with 3? Let's go through your insert method where root is the node with value 4 and val is 3.
First if-statement condition evaluates to false, so move on
Second if-statement condition evaluates to true, so create a new node with val and set root.left equal to this new node
Third if-statement condition evaluates to false, so move on
Recursive call insert(3.left, 3) just returns since 3 == 3
Recursive call insert(null, 3) just returns since root == null
So what's the fix? STOP creating new nodes at every recursive call in the call stack. Believe it or not, you should only be creating a new node when root is null, because this signifies that you've traversed the tree down to an empty child. What about the recursive calls? There's no need to do a recursive call on each of the root's children because you only go down one traversal path in a BST. You either turn left or right at each node. So what you do is only make a recursive call depending on the value of val relative to the root's value. Here's what it should look like,
private TreeNode insert (TreeNode root, int val){
if (root == null){
return new TreeNode(val);
}
if (val == root.val){
//if you don't want to add repeats in the tree, then
//add your own code to deal with that here
//although as it stands now, this code will not add repeats
}
if (val < root.val){
root.left = insert(root.left, val);
}
if (val > root.val){
root.right = insert(root.right, val);
}
return root;
}
While solving the problem that reverse first K elements of linked list i have written the below recursive code but the last iteration executing twice i.e for k=1, function call reverseNode() happening twice. Can any body why it happening like that. Please correct me if i did any thing wrong in it.
Example :
If input is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8
and k = 4 then output is
4 -> 3 -> 2 -> 1 -> 5 -> 6 -> 7 -> 8
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
Working code for my logic it is working expected. but when i try to use variable "k" in "if" condition instead of "presentCounter" then it is going wrong. Can any body tell me the reason.
public void reverseListRecursion(int count) {
this.reverseNode(null, headNode, count);
System.out.println("\n");
this.display(this.headNode);
}
/*
* Condition K <= Length of linked list.
*/
public void reverseNode(Node node, Node nextNode, int k) {
int presentCounter = k;
if (k > 1) {
k = k - 1;
this.reverseNode(nextNode, nextNode.next, k);
}
if (presentCounter == 1) {
this.kNode = nextNode.next; // Saving K's Next Node
this.headNode = nextNode; // Setting K node as head node
}
if (node == null) {
nextNode.next = this.kNode;
} else
nextNode.next = node;
}
Your recursion should be
if (k > 0) { // and not while
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
...
There are several issues with this code you provided in your question:
public void reverseListRecursion(int k) {
this.reverseNode(null, headNode,k);
}
public void reverseNode(Node node, Node nextNode,int k) {
while (k > 0) {
k = k-1;
this.reverseNode(node, nextNode.next,k);
}
if (k == 0) {
this.kNode = nextNode;
this.kNode.next = null;
}
if (node == null) {
nextNode.next = this.kNode;
} else {
nextNode.next = node;
}
}
The wile loop will make the number of recursive calls grow to k!. Maybe this was your intention, but it certainly would not make an efficient algorithm. The job can be done by moving k-1 nodes, so making k! calls is not so efficient.
The first argument (node) never changes: the recursive call just passes the same argument, and so the value you pass in the initial call (null) is what this argument will be in every call. The outcome of the last if condition will therefore always be the same. This doesn't look right.
The first if condition will always be true, because it is opposite to the while condition that precedes it. So there should be no need to make the test for k == 0.
The code within the first if block makes this.kNode a synonym for nextNode and then its next property is set to null. There should be no reason at all to set any next property to null. If anything, it will break the linked list.
In the second if block the next property of nextNode is set to ... nextNode (see previous point, which shows that this.kNode was made synonymous for nextNode). So now you have a self-referencing node, which really is something you'd never want to have. This code makes the first k+1 nodes self-referencing, thereby effectively detaching them from the original linked list.
The initial call is made with headNode as second argument. This variable is apparently a private member of the class you are in. However, after execution the reversal, headNode will still reference the node it referred to before the call. The name suggests it should point to the first node in the list, but since the reversal will move another node at the front, headNode will point to the wrong node after completion. There is no other variable or property you have that will point to the first node in the list after the reversal. this.kNode could have been it, but the statements this.kNode.next = null and nextNode.next = this.kNode are not things you would do with the first node of a list.
There are too many issues with this code to get a clear view on what you actually tried to do.
I would suggest to go for this algorithm, explained by example:
list = 1 2 3 4 5 6 7 8
k = 4
Move the node that follows the original first node to the head of the list
list = 2 1 3 4 5 6 7 8
k = 3
Move the node that follows the original first node to the head of the list
list = 3 2 1 4 5 6 7 8
k = 2
Move the node that follows the original first node to the head of the list
list = 4 3 2 1 5 6 7 8
k = 1
As k = 1 no more moves have to be made.
This is how your code would look:
public void reverseListRecursion(int k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
public Node reverseNode(Node origFirstNode, int k, Node currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
Node movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
The nice thing about this solution is that the reverseNode method does not need to reference this.headNode, and so it can be used to reverse elements in the middle of the list as well. You could add this method which takes a node as second argument:
public void reverseListRecursionAfter(int k, Node afterNode) {
afterNode.next = this.reverseNode(afterNode.next, k, afterNode.next);
};
This will reverse the nodes following the given node.
Here is a live snippet, with the same code translated to JavaScript (just for demo):
// Node class
function Node(val, next) {
this.val = val;
this.next = next;
this.toString = function (cascade) {
if (!cascade || this.next === null) return '(' + this.val + ')';
if (this.next === this) return '(' + this.val + ')-loop';
return '(' + this.val + ')->' + this.next.toString(true);
}
}
// List class
function List() {
this.headNode = null;
this.reverseListRecursion = function(k) {
// The reversal returns the node that took the first position
this.headNode = this.reverseNode(this.headNode, k, this.headNode);
};
this.reverseNode = function(origFirstNode, k, currFirstNode) {
// If 1 element needs to be reversed, there is nothing to do:
if (k <= 1) return currFirstNode;
// Move the node after the original first node before the current first node
var movingNode = origFirstNode.next;
origFirstNode.next = movingNode.next;
movingNode.next = currFirstNode;
// The moved node is now the current first node. Repeat:
return this.reverseNode(origFirstNode, k-1, movingNode);
};
this.insert = function (arr) {
for (var i = arr.length - 1; i >= 0; i--) {
this.headNode = new Node(arr[i], this.headNode);
}
}
this.toString = function () {
return '{' + this.headNode.toString(true) + '}';
}
}
var output = [];
// Sample data
var list = new List();
list.insert([1, 2, 3, 4, 5, 6, 7, 8]);
output.push('before: ' + list);
// Make the reversal call
list.reverseListRecursion(4);
output.push('after: ' + list);
// Show result in snippet
document.write(output.join('<br>'));