-2

Question:

enter image description here

My code below (doesn't work):

public K from(K k, int i) throws NotFound {
      //reset stack
      parentNode = new Stack<Node<K>>();

      //Returns node with value k
      Node<K> foundNode = findNode(k, root);

      return fromHelper(k, i, foundNode);

  } 

  public K fromHelper(K k, int i, Node<K> v) throws NotFound {


      if ( v == null ) {
          throw new NotFound();
      }
      else if (i == 0) {
          return v.key;
      }
    //Case 3: left tree exists
       if (v.left != null) {


          if (k.compareTo(v.left.key) < 0) {
              return fromHelper(k, i-1, v.left);
          }
      }
      //Case 2: Right tree exists
      if (v.right != null) {
          return fromHelper(k, i-1, v.right);
      }

       if (!parentNode.isEmpty()) {
         //Pop parent node
          Node<K> parent = parentNode.pop();
          if (k.compareTo(parent.key) < 0) {
              return fromHelper(k, i-1, parent);
          }
          else {
              throw new NotFound();
          }
      }
      else {
          throw new NotFound();
      }



  }

I am completely lost for this question. I absolutely CANNOT figure out a way to get an algorithm that run in O(log(n)) time. The ONLY algorithm I can think of is to do an in-order traversal, store values in an array and then return the ith smallest key greater than k if it exists but obviously this is worst case O(n). I have been working on this problem for the past 2 days and I simply cannot come up with a solution. The hint my professor gave me was to add a size field to the node which will tell me the number of nodes at subtree v including itself. My thinking was to try to use a relative_rank function (gives me the rank of node value k with respect to a node v) somehow but I cannot think of a way to do it in O(log(n)) time. Any help would be appreciated.

user2635911
  • 472
  • 2
  • 6
  • 16
  • First question: Why `parentNode = new Stack>()` which resets something? Maybe this should not be done? – Seelenvirtuose Jun 15 '14 at 07:28
  • Additionally, I think the algorithm is clear. 1) Find the node with the value _k_. 2) If `i == 0`, you are done. 3) If `i > 0`, you must first search the successor of your _k_ node. In an AVL tree you know where to find that. Only thing: This search must be recursive! 4) Once found, let the recursive search step back `i - 1` times. Then you have your requested node! – Seelenvirtuose Jun 15 '14 at 07:33
  • What do you mean search successor of your k node? If i > 0 aren't there three scenarios? Lets say we are at node v. First check if first node in left subtree is > k. If it is then go to it. Otherwise check right subtree > k. If it is go there. But what happens if lets say both left and right subtree of v don't yield any results. Then we must also check parent of v. Won't that step break my O(log(n)) run time? – user2635911 Jun 15 '14 at 07:53
  • [An AVL tree is a binary search tree!](http://en.wikipedia.org/wiki/AVL_tree) In a binary search tree you always know that all left nodes of _k_ are smaller than _k_ and all right nodes of _k_ are greater than _k_. So you always have to check only one of the two child nodes in each step of the algorithm. The successor of _k_ can be found that way: One step right, then step left as much as possible. _Caution: I did not think over a whole algorithm. There are many steps you have to evolve yourself. Maybe it's not as simple as I am describing it here. But it seems to be the direction._ – Seelenvirtuose Jun 15 '14 at 07:58
  • Lets say you insert the following keys in this order in an AVL tree: 37, 46, 71, 85, 68. 68 would be the left child of 71. If I call the function from (37,3) then it should return the number 68. But if I never check the left child in the algorithm I would be returning 85 which would be incorrect since the function needs to return the ith smallest key greater than k. – user2635911 Jun 15 '14 at 08:05
  • Yes, you are right. My recursive idea does not work well. But the size information (the hint) does. You could check the size of the child nodes in each step. Then you know whether the searched node must be left or right! – Seelenvirtuose Jun 15 '14 at 08:11
  • I was thinking to check if i is odd or even. If it's even it must be right child, otherwise it must be left child. But then I realized what if the answer is the root node? Then that wouldn't work. My second idea, which I spent about 2-3 hours trying to make it work was to test if size(v) <= i. – user2635911 Jun 15 '14 at 08:19
  • If it is check if v has parent. If it does then call fromHelper(k, i-i, v.parent) but after running through many test cases, I realized this approach does not work because after a certain number of recursive calls, your size(v) becomes less than i but the answer is still one of the child nodes. I honestly have no idea how else to use the size function. I've been trying for a while but I honestly cannot think of one. – user2635911 Jun 15 '14 at 08:19

1 Answers1

0

After also thinking a bit about it, I will give you some code snippets, with which you might be able to evolve the method yourself.

Precondition: You really must add the size field to each node. This size field must be updated at each insertion and deletion. And of course when rotating some sub trees.

With such a size info you should be able to do this:

public K from(K k, int i) {
    Node<K> foundNode = findNode(k, root);
    if (foundNode == null)
        throw new NotFound();
    return (i == 0)? foundNode.key : fromHelper(foundNode.right, i - 1);
}

This reflects the idea to directly stop if i == 0. If not then look into the right sub tree, as only this contains the greater values.

private K fromHelper(Node<K> node, int i) {
    if (node == null || node.size() <= i)
        throw new NotFound();
    if (i == 0)
        return node.key;

    int sizeLeft = (node.left == null)? 0 : node.left.size();
    return (sizeLeft < i)? fromHelper(node.right, i - sizeLeft) : fromHelper(node.left, i - 1);
}

The key trick is to determine the number of remaining nodes of the left sub tree (with the size info), and then to either walk to the left or the right sub tree according to that remaining number.

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66