views:

3494

answers:

10

Hi,

I need to find the kth smallest element in the binary search tree without using any static/global variable. How to achieve it efficiently? The solution that I have in my mind is doing the operation in O(n), the worst case since I am planning to do an inorder traversal of the entire tree. But deep down I feel that I am not using the BST property here. Is my assumptive solution correct or is there a better one available ?

A: 

For a binary search tree, an inorder traversal will return elements ... in order.

Just do an inorder traversal and stop after traversing k elements.

O(1) for constant values of k.

Anon.
@Anon. Thanks. But that is something that I am already aware of which is O(n) complex. My question is whether it has a better solution
Bragboy
Meh, better call it O(k). I can also say OP's solution O(1) for constant values of N.
KennyTM
Saying that's "O(1) for constant values of k" is kind of cheating. I can say any algorithm is O(1) like that...
IVlad
This is O(1) for constant values of k, regardless of the size of the tree. If k varies, it's O(k), but still independent of the tree size.
Anon.
Well, yeah we should not be carried away what value is inside big O. It merely signifies the 'rate' at which the function grows.
Bragboy
Why consider k a constant anyway? If it's a constant you can just precompute the result and of course it's O(1). And if k varies, it varies between 1 and the number of nodes in the tree, so it's not really independent of the tree size, therefore it's O(N).
IVlad
@|\/|ad: You will notice that even if k is constant, the size of the dataset is likely not.
Anon.
please...how could it be independent of the tree size? Try finding the smallest element... is that O(1)? So how could finding the k'th smallest possibly be O(1)?
Robert Lamb
@Anon: Yes, which makes it O(N) to precompute the result and O(1) to answer a query using an inorder traversal. Anyway, my point is that assuming k constant is making an unfounded assumption, as the question does not state that.
IVlad
+1 to Robert's comment. Even finding min (k=1) is O(log n) in balanced tree. (and -1 to answer).
Moron
+12  A: 

Here's just an outline of the idea:

Let each node in the BST have a field that returns the number of elements in its left and right subtree. Let the left subtree of node T contain only elements smaller than T and the right subtree only elements larger than or equal to T.

Now, suppose we are at node T:

  1. k == num_elements(left subtree of T), then the answer we're looking for is the value in node T
  2. k > num_elements(left subtree of T) then obviously we can ignore the left subtree, because those elements will also be smaller than the kth smallest. So, we reduce the problem to finding the k - num_elements(left subtree of T) smallest element of the right subtree.
  3. k < num_elements(left subtree of T), then the kth smallest is somewhere in the left subtree, so we reduce the problem to finding the kth smallest element in the left subtree.

This is O(log N) on average (assuming a balanced tree).

IVlad
To find the Nth smallest item, you only need to store the size of the left sub-tree. You'd use the size of the right sub-tree iif you also wanted to be able to find the Nth largest item. Actually, you can make that less expensive though: store the total size of the tree in the root, and the size of the left sub-tree. When you need to size of the right sub-tree, you can subtract the size of the left from the total size.
Jerry Coffin
@Jerry Coffin: true, nice observation :).
IVlad
I don't understand something. You say "k>T". k is a position like first smallest, 2nd smallest and so on. T is the value of a node right? Why compare them? And if T is also the order of a node(this is not clear to me sorry) how do I find it?
Para
@Para - I used `T` to mean the number of elements in node `T`'s left subtree (this is a bit unclear, yes, I'll edit). You find it when building the tree: once you insert a node (if you do it recursively it's easier), after you return from the recursive call on the left subtree, increment the count in the current node. Let me know if it's still not clear.
IVlad
Such an augmented BST is called an 'order statistics tree'.
Daniel
@Ivlad: in step 2: I think "k - num_elements" should be "k - num_elements -1", since you've to include root element too.
understack
@understack - not if you assume the root to be part of the subtree.
IVlad
k == num_elements(left subtree of T) .. this should be k == num_elements(left subtree of T) +1.
Anil Vishnoi
+2  A: 

Given just a plain binary search tree, about all you can do is start from the smallest, and traverse upward to find the right node.

If you're going to do this very often, you can add an attribute to each node signifying how many nodes are in its left sub-tree. Using that, you can descend the tree directly to the correct node.

Jerry Coffin
+2  A: 

If you do a search on "Order Statistics" you will find what you need.

Robert Lamb
+1  A: 

For not balanced searching tree, it takes O(n).

For balanced searching tree, it takes O(k + log n) in the worst case but just O(k) in Amortized sense.

Having and managing the extra integer for every node: the size of the sub-tree gives O(log n) time complexity. Such balanced searching tree is usually called RankTree.

In general, there are solutions (based not on tree).

Regards.

Slava
A: 

This is what I though and it works. It will run in o(log n )

public static int FindkThSmallestElemet(Node root, int k)
    {
        int count = 0;
        Node current = root;

        while (current != null)
        {
            count++;
            current = current.left;
        }
        current = root;

        while (current != null)
        {
            if (count == k)
                return current.data;
            else
            {
                current = current.left;
                count--;
            }
        }

        return -1;


    } // end of function FindkThSmallestElemet
Learner
i don't think this solution will work. What if the Kth smallest is in the right sub tree of the tree node ?
Anil Vishnoi
+3  A: 
public int ReturnKthSmallestElement1(int k)
    {
        Node node = Root;

        int count = k;

        int sizeOfLeftSubtree = 0;

        while(node != null)
        {

            sizeOfLeftSubtree = node.SizeOfLeftSubtree();

            if (sizeOfLeftSubtree + 1 == count)
                return node.Value;
            else if (sizeOfLeftSubtree < count)
            {
                node = node.Right;
                count -= sizeOfLeftSubtree+1;
            }
            else
            {
                node = node.Left;
            }
        }

        return -1;
    }

this is my implementation in C# based on the algorithm above just thought I'd post it so people can understand better it works for me

thank you IVlad

Para
A: 

Given a Binary Search Tree, write a program to print the kth smallest element without using any static/global variable. You can't pass the value k to any function also.

rachelllll
+1  A: 

This works well: status : is the array which holds whether element is found. k : is kth element to be found. count : keeps track of number of nodes traversed during the tree traversal.

int kth(struct tree* node, int* status, int k, int count)
{
    if (!node) return count;
    count = kth(node->lft, status, k, count);  
    if( status[1] ) return status[0];
    if (count == k) { 
        status[0] = node->val;
        status[1] = 1;
        return status[0];
    }
    count = kth(node->rgt, status, k, count+1);
    if( status[1] ) return status[0];
    return count;
}
pranjal
A: 

Well here is my 2 cents...

int numBSTnodes(const Node* pNode){
     if(pNode == NULL) return 0;

     return (numBSTnodes(pNode->left)+numBSTnodes(pNode->right)+1);
}


//This function will find Kth smallest element
Node* findKthSmallestBSTelement(Node* root, int k){
     Node* pTrav = root;
     while(k > 0){
         int numNodes = numBSTnodes(pTrav->left);
         if(numNodes >= k){
              pTrav = pTrav->left;
         }
         else{
              //subtract left tree nodes and root count from 'k'
              k -= (numBSTnodes(pTrav->left) + 1);

              if(k == 0) return pTrav;

              pTrav = pTrav->right;
        }

        return NULL;
 }
Manish Shukla