0

I am doing some preparations before going to interviews and i just learned about Morris Traversal.

This is Morris Traversal code which i wrote in Java(its working):

protected void morrisTraversal(){
    BinaryNode pre = null;//BinaryNode is a class which represent a node in the tree
    BinaryNode current = this.root;//root is the root of the tree
    while(current != null){
        if(current.getLeftChild() == null){
            System.out.println(current.getNodeData().getId());//id is unique
            current = current.getRightChild();
        }//if
        else{
            pre = current.getLeftChild();
            while(pre.getRightChild() != null && pre.getRightChild().getNodeData().getId() != current.getNodeData().getId())
                pre = pre.getRightChild();
            if(pre.getRightChild() == null){
                pre.setRightChild(current);
                current = current.getLeftChild();
            }//if
            else{
                System.out.println(current.getNodeData().getId());
                current = current.getRightChild();
                pre.setRightChild(null);
            }//else
        }//else
    }//while
}//MorrisTraversal

And here is my code for the In-Order method:

protected void recInOrder() {
    if(this.root != null)
        recInOrderHelper(this.root);
    else
        System.out.println("The Tree Is Empty");;
}//recInOrder


private void recInOrderHelper(BinaryNode node)  {
    if(node != null){
        recInOrderHelper(node.getLeftChild());
        System.out.println(node.getNodeData().getId());
        recInOrderHelper(node.getRightChild());
    }
}//recInOrderHelper

And what i did in my main is: I inserted to my binary tree 70,000,000 nodes and then i did the next little checking:

long start = System.currentTimeMillis();
tree4.morrisTraversalInOrder();
System.out.println("morris traversal TOOK: " + (System.currentTimeMillis() - start) + " ms");

start = System.currentTimeMillis();
tree4.recInOrder();
System.out.println("recursive in-order TOOK: " + (System.currentTimeMillis() - start) + " ms");

And the results surprised me!

Those are the results:

Morris Traversal TOOK: 637 ms

Recursive In-Order TOOK: 367 ms

NOTICE - when i did this test i commented all the System.out.println(...) from morrisTraversal() and from recInOrderHelper() methods.

Those results surprised me because i thought that Morris Traversal will be faster because its iterative(doesn't open stack frames etc) and In-Order is recursive(open approximately 70,000,000 stack frames for each recursive call)

I know that both of them are O(n), So obviously i am wrong about some things, but which? what am i missing? why Morris Traversal is much slower than recursive In-Order?

EDIT - I also did the next testing: instead of inserting 70,000,000 nodes to the tree I inserted 100,000 nodes And I did ran the next code:

//running the two algorithms one time before doing the actual test(but in the same execution)
tree4.recInOrder();
tree4.morrisTraversalInOrder();

//starting the actual test
long start = System.currentTimeMillis();
for(i = 0; i < 100000; i++){
    tree4.recInOrder(); 
}
System.out.println("Recursive In-Order TOOK: " + (System.currentTimeMillis() - start) + " ms");

start = System.currentTimeMillis();
for(i = 0; i < 100000; i++){
    tree4.morrisTraversalInOrder(); 
}
System.out.println("Morris Traversal TOOK: " + (System.currentTimeMillis() - start) + " ms");

And the results are:

Recursive In-Order TOOK: 214434 ms

Morris Traversal TOOK: 502786 ms

And as you can see Morris Traversal is still very slow compared to recursive In-Order. So I did another testing and only inserted 1,000 nodes and ran each code only 10,000 times and the result are:

Recursive In-Order TOOK: 44 ms

Morris Traversal TOOK: 97 ms

I still don't get it? why Morris Traversal is slower?

thelegend
  • 1
  • 2

3 Answers3

2

See Here you have to understand the logic . Just do dry run to morris inorder traversal let say it takes time 2k. Now do dry run for the recursive inorder traversal I am pretty much sure that you will find the time more or less k. Logic here is that Morris inorder traversal is taking more or less two times the time taken by the inorder traversal because we reaching to every node at most 2 time. once for creating dummy right link and another for removing that right link.

Now, if you are interested in space complexity then morris inorder traversal is like a king. here you don't need extra space. it's space complexity is O(1), however space complexity of the recursive inorder traversal is O(n). Hope Now u can understand the uses of both the traversal strategy. :)

  • "Morris inorder traversal is taking more or less two times the time... we reaching to every node at most 2 time. once for creating dummy right link and another for removing that right link". This explains all. I would like to add more details: If a node has no left child, it is only reached once because we will immediately turn to its right. If a node has a left child, the node as well as all nodes on the path to its inorder predecessor will be reached twice (one for creating dummy right link, and one for removing the link). – Peng Sep 16 '21 at 15:41
0

It's hard to tell without breaking the performance estimate into their components, but the Morris Traversal essentially traverses part of the tree twice when tracing back the nodes with the fake right part. You're also doing more work inside the Morris loop, so the constant factor is going to be larger. It's curious that it's almost 2x, but I wouldn't rely on that being the actual cost without further details.

dfb
  • 13,133
  • 2
  • 31
  • 52
0

You don't have a warm-up pass. You should first execute both methods, and then execute them again with timing. You're also ignoring the fact that most Java code runs in long-running processes, which eventually compiles to machine code. I would try using a smaller tree and executing the traversal many times.

David M. Karr
  • 14,317
  • 20
  • 94
  • 199