I need to perform a deep copy of a binary tree using the Morris traversal.
I think I managed to do it, that is the code below returns what I expect; however, I am not 100% sure I have covered every corner case.
I would appreciate it if someone could confirm my implementation:
- Doesn't create new nodes on top of existing nodes (i.e. leak memory)
- Won't break under some corner case tree structure (i.e. the tree has 5 left nodes in a row with no right ones or something like that).
Also, if any optimisations are possible, please let me know.
Example code:
#include <stdio.h>
#include <stdlib.h>
typedef struct tNode
{
int data;
struct tNode* left;
struct tNode* right;
}tNode;
tNode* newtNode(int data)
{
tNode* node = (tNode *)malloc(sizeof(tNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
void MorrisTraversalCopy(tNode* original, tNode** clone)
{
tNode *current = original;
tNode *cloneCurrent = newtNode(0);
tNode *pre = NULL;
tNode *clonePre = NULL;
*clone = cloneCurrent;
/* Inorder Morris traversal */
while (current != NULL)
{
if (current->left == NULL)
{
cloneCurrent->data = current->data;
current = current->right;
cloneCurrent = cloneCurrent->right;
}
else
{
/* Esure the left node is not created again when we climb back */
if(!cloneCurrent->left)
{
cloneCurrent->left = newtNode(0);
}
/* Find the inorder predecessor of current */
pre = current->left;
clonePre = cloneCurrent->left;
while (pre->right != NULL
&& pre->right != current)
{
/* Create a new right node if:
* - The pre->right has real node, not one used for climbing back
* - Only if this iteration will terminate due to
* pre->right == NULL (i.e. this is the first time the
* iteration is done) */
if(!clonePre->right && pre->right && pre->right != current)
{
clonePre->right = newtNode(0);
}
clonePre = clonePre->right;
pre = pre->right;
}
/* Make current as the right child of its
inorder predecessor */
if (pre->right == NULL)
{
clonePre->right = cloneCurrent;
cloneCurrent = cloneCurrent->left;
pre->right = current;
current = current->left;
}
/* Revert the changes made in the 'if' part to
restore the original tree i.e., fix the right
child of predecessor */
else
{
cloneCurrent->data = current->data;
/* Create a new node if it wasn't created in the while loop
* I believe this happens only on the first iteration that starts
* exploring the right subtree of the root (original) node */
if (!cloneCurrent->right)
{
cloneCurrent->right = newtNode(0);
}
clonePre->right = NULL;
cloneCurrent = cloneCurrent->right;
pre->right = NULL;
current = current->right;
}
}
}
}
void debugPrintTree(tNode *root)
{
if(root->left)
{
debugPrintTree(root->left);
}
printf("%d ", root->data);
if(root->right)
{
debugPrintTree(root->right);
}
}
int main()
{
/* Constructed binary tree is
1
/ \
2 3
/ \
4 5
/ \
6 7
\
8
*/
tNode* root = newtNode(1);
root->left = newtNode(2);
root->right = newtNode(3);
root->left->left = newtNode(4);
root->left->right = newtNode(5);
root->left->left->left = newtNode(6);
root->left->right->right = newtNode(7);
root->left->left->left->right = newtNode(8);
tNode *clone;
MorrisTraversalCopy(root, &clone);
printf("root = ");
debugPrintTree(root);
printf("\nclone= ");
debugPrintTree(clone);
return 0;
}
Please focus on the Morris Traversal function. Everything else I hacked together in a few minutes to create this post.
Also I realised I do not check for memory allocation failures and recovering from that will be tricky since the traversal modifies both trees, creating temporary loops. I am open to ideas on how to overcome this and cleanup.

tNode* node = (tNode *)malloc(sizeof(tNode));-->tNode* node = malloc(sizeof *node);. I realize that you are only interested in commentary aboutMorrisTraversalCopy, but you should be open to commentary about other code. Thismalloccall is un-idiomatic in C. Better to avoid casting the result ofmalloc, and using the expression*nodeinstead of the typetNodeis easier to maintain. \$\endgroup\$#define NEW(x) (x *) malloc(sizeof(x)). Doesn't look very wrong IMHO. \$\endgroup\$NEW(dog)to acat;-) \$\endgroup\$