-2

My professor showed the following problem in class and mentioned that the answer is O(1) while mine was quit different, I hope to get some help knowing of what mistakes did I made.

Question:

Calculate the Amortized Time Complexity for F method in AVL tree, when we start from the minimal node and each time we call F over the last found member.

Description of F: when we are at specific node F continues just like inorder traversal starting from the current one until the next one in inorder traversal for the next call.


What I did:

First I took an random series of m calls to F.

I said for the first one we need O(log n) - to find the most minimal node then for the next node we need to do inorder again but continues one more step so O(log n)+1 an so on until I scan m elements.

Which gets me to:

enter image description here

To calculate Amortized Time we do T(m)/m then I get:

enter image description here

Which isn't O(1) for sure.

1 Answers1

1

The algorithm doesn't start by searching for any node, but instead is already passed a node and will start from that node. E.g. pseudocode for F would look like this:

F(n):
     if n has right child
         n = right child of n

         while n has left child
             n = left child of n

         return n
     else
         prev = n
         cur = parent of n
         while prev is right child of cur and cur is not root
             prev = cur
             cur = parent of prev

         if cur is root and prev is right child of cur
             error "Reached end of traversal"
         else
             return cur

The above code basically does an in-order traversal of a tree starting from a node until the next node is reached.

Amortized runtime:
Pick an arbitrary tree and m. Let r_0 be the lowest common ancestor of all nodes visited by F. Now define r_(n + 1) as the lowest common ancestor of all nodes in the right subtree of r_n that will be returned by F. This recursion bottoms out for r_u, which will be the m-th node in in-order traversal. Any r_n will be returned by F in some iteration, so all nodes in the left subtree of r_n will be returned by F as well.

All nodes that will be visited by F are either also returned by F or are nodes on the path from r_0 to r_u. Since r_0 is an ancestor of r_1 and r_1 is an ancestor of r_2, etc., the path from r_0 to r_u can be at most as long as the right subtree is high. The height of the tree is limited by log_phi(m + 2), so in total at most

m + log_phi(m + 2)

nodes will be visited during m iterations of F. All nodes visited by F form a subtree, so there are at most 2 * (m + log_phi(m + 2)) edges that will be traversed by the algorithm, leading to an amortized runtime-complexity of

2 * (m + log_phi(m + 2)) / m = 2 + 2 * log_phi(m + 2) / m = O(1)

(The above bounds are in reality considerably tighter, but for the calculation presented here completely sufficient)

  • "The algorithm doesn't start by searching for any node, but instead is already passed a node and will start from that node" how did you understand this? –  Dec 15 '20 at 23:06
  • @MrCalc the description says: "we start from the minimal node and each time we call F over the last found member." –  Dec 15 '20 at 23:09
  • @MrCalc sorry, forgot a `return`-statement and and additional condition. Anyways, the code is working now. –  Dec 16 '20 at 12:44
  • and who said you have a pointer to the parent? are we allowed to assume that or to use the traditional avl tree –  Dec 16 '20 at 12:47
  • 1
    @MrCalc don't take that code too literal. Just use a stack for keeping track of parents, if your implementation of the AVL-tree doesn't provide a parent-pointer. –  Dec 16 '20 at 12:53
  • You assumed that we will conver all but that's not true, what if m< –  Dec 17 '20 at 18:33
  • 1
    @MrCalc well, the trick is that we can simply pick an arbitrary subtree containing all `m` nodes we'll pick and the above analysis gives the amortized runtime for `m` nodes. I simply left a few steps implicit, but the analysis is correct. –  Dec 17 '20 at 19:05
  • @MrCalc added the full calculation of the amortized runtime to the answer –  Dec 18 '20 at 17:01
  • Hi paul, I showed your answer for my professor and he claims it's wrong –  Dec 19 '20 at 08:00
  • @MrCalc well, thanks for the info. Did he also mention **what** was wrong? –  Dec 19 '20 at 14:03
  • ״ Let r_0 be the node in the tree such that r_0 is visited during the m iterations of F, but the parent of r_0 isn't״ there are many other cases what about those with a father whom F visited? –  Dec 24 '20 at 23:33
  • Another question, why you even care about right subtree and its height? I don't understand –  Dec 24 '20 at 23:39
  • @MrCalc `r_0` is the node such that all nodes visited by `F` are either `r_0` itself, or descendants of `r_0`. This criteria is satisfied by exactly one node for any given tree and `m`. Other cases simply can't be `r_0` and aren't suitable as starting-point of the calculation of the complexity for performing `m` steps in a given tree. –  Dec 24 '20 at 23:41
  • @MrCalc the right subtree also contains nodes that will be visited by `F`. For the left subtree the calculation is easy. But for the right subtree we need to take additional steps until we reach the next node that will be returned by `F`. Those extra-steps are limited by the height of the right subtree. –  Dec 24 '20 at 23:43
  • regarding my professor he said: can you prove that at the worst case we scan over log(m) nodes which we don't need to print in F function? I don't know why this is true at all. He told me to lock on the subtree of the nodes which we passed over –  Dec 24 '20 at 23:54
  • Plus he mentioned that those whom we don't care of are in right tree for sure which has log(m) members as maximum. Note: In you solution you never defined some things like r_n –  Dec 25 '20 at 00:06
  • In other words, I want to prove that the subtree with F travels across has O(m) members –  Dec 25 '20 at 00:07
  • @MrCalc I'd suggest we continue this in [chat](https://chat.stackoverflow.com/rooms/226400/whatever) –  Dec 25 '20 at 00:16
  • In your edited solution you just jumped to r_n without explaining what it represents –  Dec 25 '20 at 13:21
  • @MrCalc "Now define r_(n + 1) as the lowest common ancestor of all nodes in the right subtree of r_n that will be returned by F". It's just variable `r` with index `n`, which is a fairly common notation. –  Dec 25 '20 at 23:21
  • I found much easier solution, can you go chat I would like to share it with you so you would know it too :) –  Dec 30 '20 at 22:51
  • @MrCalc sure. I'm there –  Dec 30 '20 at 23:59
  • @MrCalc you could also add it as an additional answer –  Jan 01 '21 at 15:35
  • It uses the fact that traversing a tree in in-order takes 3 steps at most except for 2 nodes where we need to go from bot to top or top to bot (For example the biggest node in left subtree to the one after) –  Jan 03 '21 at 10:03
  • @MrCalc well, that still leaves the problem of figuring out how long going top-bottom and reverse takes. Also I don't quite get where you got those three steps from. You should either add your solution as an answer, if you're confident that it's correct, or just send it in chat, if you want me to check it. –  Jan 05 '21 at 00:59