Morris Traversal本来是一种中续遍历的经典算法,相对于递归与使用椎的遍历。不需要额外的空间,也就是说空间复杂度为O(1)。
leetcode 中关于二叉树3种遍历方式的题,其中要求不能用递归。那么Morris就是一种可取的方案。
以下都是leetcode oj接受了的解。
经典中续
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int buff[255];
*returnSize=0;
struct TreeNode *cur=root;
struct TreeNode *prev=NULL;
while(cur){
if(cur->left){
prev=cur->left;
while(prev->right && prev->right!=cur)
prev=prev->right;
if(prev->right){
// just come from precessor
prev->right=NULL;
buff[*returnSize]=cur->val;
++(*returnSize);
cur=cur->right;
}else{
prev->right=cur;
cur=cur->left;
}
}else{
buff[*returnSize]=cur->val;
++(*returnSize);
cur=cur->right;
}
}
int bs=sizeof(int)*(*returnSize);
int *res=malloc(bs);
memcpy(res,buff,bs);
return res;
}
算法的关键在于使用当前结点左结点的最右结点的空指针,指回当前结点用于遍历的时候回退。事实上这个结点正好是当前结点的中续遍历的前驱结点。
稍微修改就得到了先续遍历
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
int buff[255];
*returnSize=0;
struct TreeNode *cur=root;
struct TreeNode *prev=NULL;
while(cur){
if(cur->left){
prev=cur->left;
while(prev->right && prev->right!=cur)
prev=prev->right;
if(prev->right){
// just come from precessor
prev->right=NULL;
cur=cur->right;
}else{
prev->right=cur;
buff[*returnSize]=cur->val;
++(*returnSize);
cur=cur->left;
}
}else{
buff[*returnSize]=cur->val;
++(*returnSize);
cur=cur->right;
}
}
int bs=sizeof(int)*(*returnSize);
int *res=malloc(bs);
memcpy(res,buff,bs);
return res;
}
后续的情况更加复杂一些。主要的区别是要逆向输出当前结点左结点的右子树。所以root结点需要一个额外的结点来辅助完成遍历。
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
int buff[255];
*returnSize=0;
struct TreeNode dump;
dump.left=root;
dump.right=NULL;
dump.val=0;
struct TreeNode *cur=&dump;
struct TreeNode *prev=NULL;
while(cur){
if(cur->left){
prev=cur->left;
while(prev->right && prev->right!=cur)
prev=prev->right;
if(prev->right){
// just come from precessor
struct TreeNode *p=cur->left;
int rn=0;
while(p!=cur){
buff[*returnSize]=p->val;
++(*returnSize);
p=p->right;
++rn;
}
//reverse right branch vals
int pt=*returnSize -1;
int ph=(*returnSize -rn);
while(pt>ph){
int tmp=buff[ph];
buff[ph]=buff[pt];
buff[pt]=tmp;
--pt;
++ph;
}
prev->right=NULL;
cur=cur->right;
}else{
prev->right=cur;
cur=cur->left;
}
}else{
cur=cur->right;
}
}
int bs=sizeof(int)*(*returnSize);
int *res=malloc(bs);
memcpy(res,buff,bs);
return res;
}