I did the LeetCode question Binary Search Tree Iterator. the following code is what I learned from others. One part I didn't understand which is cur = cur.right. Since I got the smallest value of cur.val. Why do I need to assign cur.right to cur? When I remove cur = cur.right, it said time limit exceeded. Could someone can help me to explain it?
public class BSTIterator {
Stack<TreeNode> stack;
TreeNode cur;
public BSTIterator(TreeNode root) {
stack = new Stack<>();
cur = root;
}
/** #return the next smallest number */
public int next() {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
int val = cur.val;
cur = cur.right; //why needed to assign cur.right to cur?
return val;
}
}
By thinking on the structure of a binary search tree we know that the left node is less than the parent (or middle) node, and that the right node is more than the parent (or middle) node. By setting the current node to be equal to the right node you are iterating through the tree in order from least to largest value. Note that if cur.right() doesn't exist then cur will be set to null and therefore not execute the while loop.
I submitted my code, it was successful.
https://leetcode.com/problems/binary-search-tree-iterator/
You can find it here.
https://github.com/yan-khonski-it/bst/blob/master/bst-core/src/main/java/com/yk/training/bst/iterators/BSTIterator.java
Explanation.
You have to use inorder which first visits the left sub-tree, then visit the current node, and then the right sub-tree, so you will iterate through all the elements in the ascending order.
Now, you have stack, which holds all the node that you should return in next call in the correct order.
next will remove the last element from the stack. Now you check the current node, if it has right subtree. If so, you need to iterate though left elements of the right subtree.
/**
* Find next node to be returned in {#link #next()}.
* Push it to stack.
*/
public void navigateLeftSubtree() {
stack.push(currentNode);
while (currentNode.left != null) {
currentNode = currentNode.left;
stack.push(currentNode);
}
}
In this case, (right sub tree is present for current node), you should put the right child of the current node into the stack. You don't want to put the current into the stack, if you have already visited it.
public int next() {
currentNode = stack.pop();
final int currentValue = currentNode.value;
if (currentNode.right != null) {
// Push root of the right subtree into stack.
currentNode = currentNode.right;
navigateLeftSubtree();
}
return currentValue;
}
Related
I am currently working on a Binary Search Tree project, and I would like to implement an "inorder" visit function:
void inorder(struct node *root)
{
if(root!=NULL) // checking if the root is not null
{
inorder(root->left_child); // visiting left child
printf(" %d ", root->data); // printing data at root
inorder(root->right_child);// visiting right child
}
}
However I do have a little issue, my BST varies between 100000 and 1000000 keys, and as you can imagine, printing them all is not very "handy". Is there perhaps a way to modify this inorder function in a way that it only prints "The BST is in order"? I have been trying to implement it but I really can't find a solution.
Thanks in advance for your help! Wish you a lovely coding session!
It looks like you want to verify whether a tree is actually a valid BST, i.e. its in-order traversal would visit its values in non-decreasing order.
For that you need a different function. Here is how it could be done:
int isValidBstHelper(struct node *root, int low, int high) {
return root == NULL ||
(root->data >= low && root->data <= high &&
isValidBstHelper(root->left_child, low, root->data) &&
isValidBstHelper(root->right_child, root->data, high));
}
int isValidBst(struct node *root) {
return isValidBstHelper(root, INT_MIN, INT_MAX);
}
isValidBst will return 1 when the tree is a valid BST and 0 when it is not.
To print the result, just call like this:
if (isValidBst(root)) {
printf("The tree is a valid BST");
} else {
printf("The tree is NOT a valid BST");
}
void insert(struct node *root, string s)
{
struct node *temp = root;
for(int i=0;i<s.length();i++)
{
if(temp->idx[s[i]-'a']==NULL)
temp->idx[s[i]-'a']=create();
temp = temp->idx[s[i]-'a'];
(temp->cnt)++;
}
temp->end=1;
}
So I am going to insert string to create a unique trie data structure, but this insert algortihm is not able to detect any duplicate string, can someone help me how this insert algorithm works only for inserting unique elements?
You can check for string duplicates using end property of struct node. Let's call find to this boolean method and add it as first line of insert method.
bool find(struct node *root, string s)
{
struct node *temp = root;
for(int i=0;i<s.length();i++)
{
if(temp->idx[s[i]-'a']==NULL)
return false;
temp = temp->idx[s[i]-'a'];
}
return temp->end;
}
void insert(struct node *root, string s)
{
if(!find(root, s)) return;
struct node *temp = root;
for(int i=0;i<s.length();i++)
{
if(temp->idx[s[i]-'a']==NULL)
temp->idx[s[i]-'a']=create();
temp = temp->idx[s[i]-'a'];
(temp->cnt)++;
}
temp->end=1;
}
Runtime: The same as before O(m) where m is length of s.
Note: I made find method since anyway you need to traverse at most twice that path of the trie. One way is the mentioned at the beginning, a second one is to check duplicates (end property) when you have the node that represent s and if it is indeed a duplicated string then you traverse again s path fixing the extra +1 in cnt property.
Some of the code below seems too obvious, traversing the tree using its right most branch since that is where all the max values are.However, I don't understand a few things about this code I saw in Robert Sedgewick's Algorithms book.
public void deleteMax() {
if (isEmpty()) throw new NoSuchElementException("");
root = deleteMax(root);
assert check();
}
private Node deleteMax(Node x) {
if (x.right == null) return x.left;
x.right = deleteMax(x.right);
x.size = size(x.left) + size(x.right) + 1;
return x;
}
In the private method why do we return the left element if the right child of x is null ?From my understanding x would be the maximum if x has no right children and is the right most node we could go to.Also I don't understand when do we return x in the last line of the 2nd method.
If x doesn't have a right child then x is the maximum node. We "delete" it by returning x.left (the new max node). We return x after we've modified its right subtree.
This code is for Aho-Corasick algorithm which i have refereed from here
I understood this code up to if block of push_links method but i didn't get the use or requirement for the else part of the same method.
More specifically first method is used for the construction of trie. The remaining work is done by second method i.e linking the node to their longest proper suffix which are prefix of some pattern also. This is carried out by the If block then what is the need of else part.
Please help me in this.
const int MAXN = 404, MOD = 1e9 + 7, sigma = 26;
int term[MAXN], len[MAXN], to[MAXN][sigma], link[MAXN], sz = 1;
// this method is for constructing trie
void add_str(string s)
{
// here cur denotes current node
int cur = 0;
// this for loop adds string to trie character by character
for(auto c: s)
{
if(!to[cur][c - 'a'])
{
//here two nodes or characters are linked using transition
//array "to"
to[cur][c - 'a'] = sz++;
len[to[cur][c - 'a']] = len[cur] + 1;
}
// for updating the current node
cur = to[cur][c - 'a'];
}
//for marking the leaf nodes or terminals
term[cur] = cur;
}
void push_links()
{
//here queue is used for breadth first search of the trie
int que[sz];
int st = 0, fi = 1;
//very first node is enqueued
que[0] = 0;
while(st < fi)
{
// here nodes in the queue are dequeued
int V = que[st++];
// link[] array contains the suffix links.
int U = link[V];
if(!term[V]) term[V] = term[U];
// here links for the other nodes are find out using assumption that the
// link for the parent node is defined
for(int c = 0; c < sigma; c++)
// this if condition ensures that transition is possible to the next node
// for input 'c'
if(to[V][c])
{
// for the possible transitions link to the reached node is assigned over
// here which is nothing but transition on input 'c' from the link of the
// current node
link[to[V][c]] = V ? to[U][c] : 0;
que[fi++] = to[V][c];
}
else
{
to[V][c] = to[U][c];
}
}
}
IMO you don't need the else-condition. If there is no children either it's already a link or nothing.
There are some variations of Aho-Corasick algorithm.
Base algorithm assumes that if edge from current node (cur) over symbol (c) is missing, then you go via suffix links to the first node that has edge over c (you make move via this edge).
But your way over suffix links is the same (from the same cur and c), because you don't change automaton while searching. So you can cache it (save result of
// start from node
while (parent of node doesn't have an edge over c) {
node = parent
}
// set trie position
node = to[node][c]
// go to next character
in to[node][c]. So next time you won't do this again. And it transfrom automaton from non-deterministic into deterministic state machine (you don't have to use link array after pushing, you can use only to array).
There are some problems with this implementation. First, you can get an index of string you found (you don't save it). Also, len array isn't used anywhere.
For
means, this algorithm is just checking the existence of the character in the current node link using "link[to[V][c]] = V ? to[U][c] : 0;". should not it verify in the parents link also?
Yes, it's ok, because if to[U][c] is 0, then there are no edges via c from all chain U->suffix_parent->suffix parent of suffix_parent ... -> root = 0. So you should set to[V][c] to zero.
I want to implement a stack (push and pop operations) using a BST.
During post order traversal in a BST, root is placed at the top in the stack, while traversing iteratively.
So, does that mean I have to insert and delete elements from the root or something else?
int num=1;
struct node
{
int flag;
int val;
node *left,*right,*parent;
};
node* tree::InorderTraversalusingInBuiltstack()
{
stack<node *> p;
node *current=root;
while(!p.empty()|| current!=NULL)
{
while(current!=NULL)
{
p.push(current);
current=current->left;
}
current=p.top();
if(current->flag==num)
{
return current;
}
p.pop();
current=current->right;
}
}
void tree::StackUsingBST()
{
node *q;
while(root!=NULL)
{
num--;
q=InorderTraversalusingInBuiltqueue();
node *a=q->parent;
if(a!=NULL)
{
if(a->left==q)
a->left=NULL;
else
a->right=NULL;
q->parent=NULL;
delete q;
disp();
cout<<endl;
}
else
{
delete q;
root=NULL;
}
}
}
Here my approach is that i modified my data structure a bit, by using a flag variable
as a global variable;
suppose first i insert 8 then its corresponding flag value is 1
then insert 12 its flag value=2
then insert 3 its flag value=3
now inorder to use BST as a stack I have to delete the element which has been inserted last , and according to my algo having highest flag value.
Also note that the last element inserted will not have any child so its deletion is quite easy.
In order to find the highest flag value available with the nodes, I did a inordertraversal using stack which is better than its recursive traversal.
After finding that node corresponding to highest flag value ,I delete that node.
this process is repeated until root=NULL.