How does the integers placed inside a tree structure? really confusing - data-structures

So far i know that small value integers is placed at LHS and big value is placed at RHS. Can anyone give a good explanation. Thank you

Just to go over the background (skip this if you know it already):
A tree is a collection of nodes connected by edge with no loops allowed. The topmost node is called the root node. Nodes can have zero or more child nodes, which are nodes that extend downward from it. All nodes have exactly one parent node that extends upward from it (the root is the exception and has not parents). Allowing more than one parent would create loops, which are not allowed in trees.
A binary tree is a special type of tree where every node has at most two child nodes. All nodes in a binary tree have a value, a left pointer and a right pointer. The pointers point to the left and right child nodes, if they exist. If they don't exist, the pointers are NULL pointers don't point anywhere.
A binary search tree is a special type binary tree where the nodes are organized in a special way:
given any node, all nodes in its left subtree will have a lesser value
given any node, all nodes in its right subtree will have a greater value
Binary search trees are organized like this to allow for easy searching of values.
Now for the insertion algorithm...
Let's say we are given the number 3 to insert into the following tree:
6
/ \
4 9
/ \ /
2 5 8
All we need to do is start at the root and descend down the tree, going left if our new value less than the node value, and right if the our new value is greater. We stop when we find an empty space to insert out node.
So to insert the number 3...
start at the top node
3 is less than 6, so go left
3 is less than 4, so go left
3 is greater than 2, so go right
we've found empty space for a new node, so insert it here
6
/ \
4 9
/ \ /
2 5 8
\
3
The Insert() procedure can be defined recursively. Once we decide to move left or right, we can just focus on the subtree below the current node and forget about the rest of the tree.
In pseudocode:
Insert(Node root, int newValue)
if (root is empty)
Node N = new Node
N.value = newValue
else if (root.value < newValue)
Insert(root.left, newValue)
else if (root.value > newValue)
Insert(root.left, newValue)

Related

Generate all the leaf to leaf path in an n-array tree

Given an N-ary tree, I have to generate all the leaf to leaf paths in an n-array tree. The path should also denote the direction. As an example:
Tree:
1
/ \
2 6
/ \
3 4
/
5
Paths:
5 UP 3 UP 2 DOWN 4
4 UP 2 UP 1 DOWN 6
5 UP 3 UP 2 UP 1 DOWN 6
These paths can be in any order, but all paths need to be generated.
I kind of see the pattern:
looks like I have to do in order traversal and
need to save what I have seen so far.
However, can't really come up with an actual working algorithm.
Can anyone nudge me to the correct algorithm?
I am not looking for the actual implementation, just the pseudo code and the conceptual idea would be much appreciated.
The first thing I would do is to perform in-order traversal. As a result of this, we will accumulate all the leaves in the order from the leftmost to the rightmost nodes.(in you case this would be [5,4,6])
Along the way, I would certainly find the mapping between nodes and its parents so that we can perform dfs later. We can keep this mapping in HashMap(or its analogue). Apart from this, we will need to have the mapping between nodes and its priorities which we can compute from the result of the in-order traversal. In your example the in-order would be [5,3,2,4,1,6] and the list of priorities would be [0,1,2,3,4,5] respectively.
Here I assume that our node looks like(we may not have the mapping node -> parent a priori):
class TreeNode {
int val;
TreeNode[] nodes;
TreeNode(int x) {
val = x;
}
}
If we have n leaves, then we need to find n * (n - 1) / 2 paths. Obviously, if we have managed to find a path from leaf A to leaf B, then we can easily calculate the path from B to A. (by transforming UP -> DOWN and vice versa)
Then we start traversing over the array of leaves we computed earlier. For each leaf in the array we should be looking for paths to leaves which are situated to the right of the current one. (since we have already found the paths from the leftmost nodes to the current leaf)
To perform the dfs search, we should be going upwards and for each encountered node check whether we can go to its children. We should NOT go to a child whose priority is less than the priority of the current leaf. (doing so will lead us to the paths we already have) In addition to this, we should not visit nodes we have already visited along the way.
As we are performing dfs from some node, we can maintain a certain structure to keep the nodes(for instance, StringBuilder if you program in Java) we have come across so far. In our case, if we have reached leaf 4 from leaf 5, we accumulate the path = 5 UP 3 UP 2 DOWN 4. Since we have reached a leaf, we can discard the last visited node and proceed with dfs and the path = 5 UP 3 UP 2.
There might be a more advanced technique for solving this problem, but I think it is a good starting point. I hope this approach will help you out.
I didn't manage to create a solution without programming it out in Python. UNDER THE ASSUMPTION that I didn't overlook a corner case, my attempt goes like this:
In a depth-first search every node receives the down-paths, emits them (plus itself) if the node is a leaf or passes the down-paths to its children - the only thing to consider is that a leaf node is a starting point of a up-path, so these are input from the left to right children as well as returned to the parent node.
def print_leaf2leaf(root, path_down):
for st in path_down:
st.append(root)
if all([x is None for x in root.children]):
for st in path_down:
for n in st: print(n.d,end=" ")
print()
path_up = [[root]]
else:
path_up = []
for child in root.children:
path_up += child is not None and [st+[root] for st in print_root2root(child, path_down + path_up)] or []
for st in path_down:
st.pop()
return path_up
class node:
def __init__(self,d,*children):
self.d = d
self.children = children
## 1
## / \
## 2 6
## / \ /
## 3 4 7
## / / | \
## 5 8 9 10
five = node(5)
three = node(3,five)
four = node(4)
two = node(2,three,four)
eight = node(8)
nine = node(9)
ten = node(10)
seven = node(7,eight,nine,ten)
six = node(6,None,seven)
one = node(1,two,six)
print_leaf2leaf(one,[])

Deletion a Node from binary search tree with 2 nodes, with a different method possible?

I have searched everywhere for this but there is only one method :
find predecessor (or successor) of node to delete
replace node with predecessor (or successor)
delete predecessor (or successor)
But i feel we can also do in this way :
pulloff the right(or left) element to the node to delete i.e just replace the
element to delete with right (or left) element and keep doing it till we encounter
the leaf and then delete the leaf.
In brief, keep replacing element to delete with its right(or left) element and keep doing it till we reach the leaf , and then delete the leaf.
So Is this method right ?
Unfortunately CoderAj, the solution provided by Vikhram is the correct way to delete a node in BST.
Your approach sounds good, but fails in the first replace itself.
Let's work out your approach on a tree.
8
5 25
3 7 23 30
6 24 27 35
Let us delete the root i.e. 8
Step 1:
25 //replaced 8 by 25
5 25
3 7 23 30
6 24 27 35
23 and 24 are less than 25, and still they lie in its right sub-tree.
Thus, your final tree would look like this
25
5 30
3 7 23 35
6 24 27
which does not look like a Binary Search tree.
I don't truly follow your algorithm (both of them). But below is how you delete a node from a Binary Tree (non-balancing).
Find the node to be deleted. This node can only be replaced by one of the 2 nodes in the existing tree
1. The leftmost (i.e. smallest) element of your right child node or
2. The rightmost (i.e. largest) element of your left child node.
Replace it with whichever is available and you are done
No other nodes need to be moved since
1. RightMostChildOfLeftChild() < CurrentNode() < LeftMostChildOfRightChild()
2. No nodes exist between RightMostChildOfLeftChild() and LeftMostChildOfRightChild() other than the CurrentNode()
Now if you don't mind just moving a bunch of nodes around, then there are lot of other ways to delete a node.
Hope that clarifies it for you.
For your subject question, the answer is yes; another method is possible.
There is a way that I discovered in a book of Sedgewick, which in my opinion is easier and general.
First, consider the exclusive join of two BST ts and tg'. Exclusive means that all the keys intsare smaller than any key intg`. So consider the following situation:
Now, if you select any root between ts or tg as the root of the exclusive join, you could recursively define the definitive result as follows:
In this case the root of the join is the root of ts.
Note that when you delete a complete node in a BST, its children are two exclusive trees in the sense previously defined. So you could define the deletion as follows:
Node * remove_from_bst(Node *& root, int key) noexcept
{
if (root == nullptr)
return nullptr; // In this case key was not found
// recursive searching of the key to be removed
if (key < root->key)
return remove_from_bst(root->left, key);
else if (root->key < key)
return remove_from_bst(root->right, key);
// here root contains a node with key
Node * ret_val = root; // backup of root that we will remove from tree
root = join_exclusive(root->left, root->right); // new subtree
return ret_val; // we return the removed node
}
Now, for finishing, we define the join_exclusive() operation:
Node * join_exclusive(Node *& ts, Node *& tg) noexcept
{
if (ts == nullptr)
return tg;
if (tg == nullptr)
return ts;
tg->left = join_exclusive(ts->right, tg->left);
ts->right = tg;
Node * ret_val = ts;
ts = tg = nullptr; // empty the trees
return ret_val;
}
This approach is for me easier because it manages the three cases: a leaf, an incomplete node and a complete node. In addition, the keys never are moved between nodes.
Since the root of the exclusive join is arbitrarily selected, this approach, as well as the yours, introduces a bias that tends to unbalance a random tree (the root selection was not randomly done). However, as Martinez & Roura propose for their random trees, you could store the cardinality of each subtree in the node. Then, you could perform a raffle that ponderates the cardinalities of each subtree. With this approach you could guarantee that the tree always is equivalent to a BST randomly built

Exercise review Trees binary c++

Given a binary tree, whose root is located a treasure, and whose internal nodes can contain a dragon or does not contain anything, you are asked to design an algorithm that tells us the leaf of the tree whose path to the root has the lowest number of dragons. In the event that there are multiple paths with the same number of dragons, the algorithm will return that which is more to the left of all them. To do this, implement a function which gets a binary tree whose nodes store integers:
The root contains the integer 0, which represents the treasure.
The internal nodes contain the integer 1 to indicate that the node there is a dragon or the integer 2 to indicate that there is no dragon.
In each leaf stores an integer greater than or equal to 3 that cannot be repeated. and return the whole sheet to the path selected. The tree has at least one root node and a leaf node different from the root. For example, given the following tree (the second test case shown in the example), the algorithm return the integer 4.
I can not upload a picture of the tree of example, but someone tell me with words that I can do to go through all the branches, and to know which is the path with less dragons I'd appreciate it.
A greeting!
You want to think about these problems recursively: if you're at a parent node with...
no children you must have no dragon and a node counter, and you consider yourself to have 0 dragons and be the best node: you'd tell your parent that if asked
a left branch and/or a right branch, then you ask your children for their dragon-count and which node they consider best, and IF the left node reports a lesser or equal dragon count...
you take your best-node and dragon-count from it, ELSE
you take your best-node and dragon-count from the right node
then you add 1 to the dragon-count if your node's storing the integer 1
By starting that processing at the root node, you get the result for the entire tree.
This is the first algorithm that comes to mind. Assuming that you have an array that stores the values in nodes node_value[NODE_NUM], where NODE_NUM is the number of nodes in your tree, and you store index of childs of each node with the arrays left[NODE_NUM] and right[NODE_NUM], and your root will have index root_index. We will store information about the number of dragons in the path to root in the array dragon[NODE_NUM] So the algorithm pseudocode is:
# the recursive function itself
process(node_index):
n_left <- 0
if node_value[left[node_index]] = 1
n_left <- 1
n_right <- 0
if node_value[right[node_index]] = 1
n_right <- 1
dragon[left[node_index]] <- dragon[node_index] + n_left
dragon[right[node_index]] <- dragon[node_index] + n_right
process(left[node_index])
process(right[node_index])
# the number of dragons in path from root to root is, obviously, zero:
dragon[root_index] <- 0
# Call the function itself
process(root_index)
After that, in dragon we will have the number of dragons in the way to root from every nodes in tree. Now, all you have to do is to loop through all nodes and find the node that is a leaf and that its values is minimal:
min <- infinity
node_min <- unknown
for each node:
if node_value[node] >= 3:
if dragon[node] < min:
min <- dragon[node]
node_min <- node
return node_min
Now, the node_min is the node that has least dragons in the path to root.

Pseudo Code and conditions for deleting a Node in Binary Search Tree

I'm trying to write a function to remove a node from a binary tree. I haven't coded the function yet, and I am trying to think about the different conditions I should consider for removing a node. I am guessing that the possible conditions are:
The node has no children
The node has one child
The node has 2 children
In each of these cases what would be the algorithm to perform a delete function?
This is something you would find in any standard textbook about algorithms, but let's suppose you are interested in the unbalanced case (balanced trees usually performs some rebalancing operations called "rotations" after a removal) and you use the "obvious" datastructure (a tree_node structure that holds the value and two pointers to other tree_node):
No children: release the memory hold by the node and set the parent's child link that pointed to it as NULL;
One child: release the memory hold by the node and set the parent's child link that pointed to it as the address of its unique child;
Two children: this is indeed the "complicated" case. Find the rightmost node of the left child (or the leftmost node of the right child), take its value, remove it (it is "case 1", so it is easy and can be done recursively) and set the current node's value as the one of that node. This is O(tree_height) = O(n), but it is not a problem (at least in theory) because this would be neverthless the complexity of finding a node.
Does your tree have any additional properties?
Is it an AVL?
If not, there are some pretty obvious and straightforward ways to do what you want (which will depend on your data representation, as Vitalij said).
And if it is an AVL for example, there ALSO are some well known method for doing that (wikipedia will tell you more on that topic)
First task is to find whether node exists which will be done during search and rest of your conditions are correct.
Leaf node: set the parent's child (right/left) to NULL.
Has one child: Just set the child of the node to be deleted to its parent's child.
Has two children: Basically have to re-order the whole subtree here by pruning the subtree to by finding new children for the node to be deleted.
Assuming you are dealing with general binary trees, do the following,
Node has no child- ie it is a leaf : Conveniently delete it..
Node has one child - Make the parent of the node to be deleted parent of its child , then delete the node. ie, if A->Parent = B; C->Parent = A; and A has to be deleted, then 1. Make C->Parent = B; 2. Delete A;
Tricky one.... Yes, replacing the node to be deleted by the left most child of the right subtree work, or by the rightmost tree of the left subtree, either will do... because it can be seen like this,
When a node is deleted, it has to be replaced by a node which satisfies some properties...
Lets say if our binary tree represents sorted numbers (in increasing order) in inorder traversal, then the deleted node should be replaced by some node from either of its subtrees. That should be larger in value than the whole remaining left subtree, and smaller than the whole remaining right subtree (remaining means the subtree remaining after adjusting for the deleted node successfully). Only two such nodes exist, leftmost leaf of the right subtree, or the rightmost node of left one.
Hence, replacing the deleted node from either one suffices...!!
Delete the given keys one at a time from the binary search tree. Possible equal keys were inserted into the left branch of the existing node. Please note that the insertion strategy also affects how the deletion is performed
BinarySearchTree-Delete
Node Delete(Node root, Key k)
1 if (root == null) // failed search
2 return null;
3 if (k == root.key) // successful search
4 return DeleteThis(root);
5 if (k < root.key) // k in the left branch
6 root.left = Delete(root.left, k);
7 else // k > root.key, i.e., k in the right branch
8 root.right = Delete(root.right, k);
9 return root;
Node DeleteThis(Node root)
1 if root has two children
2 p = Largest(root.left); // replace root with its immediate predecessor p
3 root.key = p.key;
4 root.left = Delete(root.left, p)
5 return root;
6 if root has only left child
7 return root.left
8 if root has only right child
9 return root.right
10 else root has no children
11 return null
Node Largest(Node root)
1 if root has no right child
2 return root
3 return Largest(root.right)

Sum up child values and save the values calculated in intermediate steps

struct node {
int value;
struct node* left;
struct node* right;
int left_sum;
int right_sum;
}
In a binary tree, from a particular node, there is a simply recursive algorithm to sum up all its child values. Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
Will it be easier to do this bottom up by adding a struct node* parent link to the node definition?
No, this is clearly an exercise in recursion. Think about what the sum means. It's zero plus the "sum of all values from the root down".
Interestingly enough, the "sum of all values from the root down" is the value of the root node plus the "sum of all values from its left node down" plus the "sum of all values from its right node down".
Hopefully, you can see where I'm going here.
The essence of recursion is to define an operation in terms of similar, simpler, operations with a terminating condition.
The terminating condition, in this case, is the leaf nodes of the tree or, to make the code simpler, beyond the leaf nodes.
Examine the following pseudo-code:
def sumAllNodes (node):
if node == NULL:
return 0
return node.value + sumAllNodes (node.left) + sumAllNodes (node.right)
fullSum = sumAllNodes (rootnode)
That's really all there is to it. With the following tree:
__A(9)__
/ \
B(3) C(2)
/ \ \
D(21) E(7) F(1)
Using the pseudo-code, the sum is the value of A (9) plus the sums of the left and right subtrees.
The left subtree of A is the value of B (3) plus the sums of its left and right subtrees.
The left subtree of B is the value of D (21) plus the sums of its left and right subtrees.
The left subtree of D is the value of NULL (0).
Later on, the right subtree of A is the value of C (2) plus the sums of its left and right subtrees, it's left subtree being empty, its right subtree being F (1).
Because you're doing this recursively, you don't explicitly ever walk your way up the tree. It's the fact that the recursive calls are returning with the summed values which gives that ability. In other words, it happens under the covers.
And the other part of your question is not really useful though, of course, there may be unstated requirements that I'm not taking into account, because they're, well, ... unstated :-)
Is there a way to save the values calculated in the intermediate steps and store them as left_sum and right_sum in child nodes?
You never actually re-use the sums for a given sub-tree. During a sum calculation, you would calculate the B-and-below subtree only once as part of adding it to A and the C-and-below subtree.
You could store those values so that B contained both the value and the two sums (left and right) - this would mean that every change to the tree would have to propagate itself up to the root as well but it's doable.
Now there are some situations where that may be useful. For example, if the tree itself changes very rarely but you want the sum very frequently, it makes sense performance wise to do it on update so that the cost is amortised across lots of reads.
I sometimes use this method with databases (which are mostly read far more often than written) but it's unusual to see it in "normal" binary trees.
Another possible optimisation: just maintain the sum as a separate variable in the tree object. Initialise it to zero then, whenever you add a node, add its value to the sum.
When you delete a node, subtract its value from the sum. That gives you your very fast O(1) "return sum" function without having to propagate upwards on update.
The downside is that you only have a sum for the tree as a whole but I'm having a hard time coming up with a valid use case for needing the sum of subtrees. If you have such a use case, then I'd go for something like:
def updateAllNodes (node):
if node == NULL:
return 0
node.leftSum = updateAllNodes (node.left)
node.rightSum = updateAllNodes (node.right)
return node.value + node.leftSum + node.rightSum
change the tree somehow (possibly many times)
fullSum = updateAllNodes (root)
In other words, just update the entire tree after each change (or batch the changes then update if you know there's quite a few changes happening). This will probably be a little simpler than trying to do it as part of the tree update itself.
You can even use a separate dirtyFlag which is set to true whenever the tree changes and set to false whenever you calculate and store the sum. Then use that in the sum calculation code to only do the recalc if it's dirty (in other words, a cache of the sums).
That way, code like:
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
fullSum = updateAllNodes (root)
will only incur a cost on the first invocation. The other four should be blindingly fast since the sum is cached.

Resources