[基本算法] morris(空间复杂度为O(1)的二叉树遍历算法)

morris算法空间复杂度为O(1),时间复杂度为O(N)

核心思想是使用节点的左子树最右叶节点的右指针指向节点。其特点在于:

每个节点的左子树最右节点都不同,不用担心冲突;

可以不保存原节点的指针,进行右移动时会自动回到子树的根节点;

通过判断最右节点是否指向当前节点可以知道是否已遍历过左子树;

 

其基本算法步骤如下:

当前节点为cur

1.若节点有左子树

寻找左子树最右根节点mostRight;

a.若mostRight->right指向null,则令其指向cur,cur左移;

b.若mostRight->right指向cur,说明左子树已遍历完毕,令其指向null,cur右移;

2.若节点无左子树

cur右移;


前序遍历

若节点左子树为空,立刻访问;

若mostRight右指针指向空(即首次到当前此节点cur),立刻访问;

 1 void morrisPre(TreeNode *root){
 2     if(root==nullptr)
 3         return ;
 4     TreeNode *cur=root, *mostRight=nullptr;
 5 
 6     while(cur!=nullptr){
 7         if(cur->left!=nullptr){
 8             //有左子树,寻找mostright节点
 9             mostRight=cur->left;
10             //寻找左子树最右节点,注意避免回到当前节点
11             while(mostRight->right!=nullptr && mostRight->right!=cur)
12                 mostRight=mostRight->right;
13             
14             if(mostRight->right==nullptr){
15                 //若mostRight指向空,则令其指向cur,cur左移
16                 cout<<cur->val<<endl;
17                 mostRight->right=cur;
18                 cur=cur->left;
19             }
20             else if(mostRight->right==cur){
21                 //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动
22                 mostRight->right=nullptr;
23                 cur=cur->right;
24             }
25         }
26         else{
27             //无左子树,让cur向右移动
28             cout<<cur->val<<endl;
29             cur=cur->right;
30         }
31     }
32 }

 

中序遍历

若节点左子树为空,立即访问;

若mostRight右指针指向节点本身(当前节点cur左子树已被访问),立即访问;

void morrisMid(TreeNode *root){
    if(root==nullptr)
        return ;
    TreeNode *cur=root, *mostRight=nullptr;

    while(cur!=nullptr){
        if(cur->left!=nullptr){
            //有左子树,寻找mostright节点
            mostRight=cur->left;
            //寻找左子树最右节点,注意避免回到当前节点
            while(mostRight->right!=nullptr && mostRight->right!=cur)
                mostRight=mostRight->right;
            
            if(mostRight->right==nullptr){
                //若mostRight指向空,则令其指向cur,cur左移
                mostRight->right=cur;
                cur=cur->left;
            }
            else if(mostRight->right==cur){
                //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动
                cout<<cur->val<<endl;

                mostRight->right=nullptr;
                cur=cur->right;
            }

        }
        else{
            //无左子树,让cur向右移动
            cout<<cur->val<<endl;
            cur=cur->right;
        }

    }
}

 

后续遍历

仅在碰到mostRight右指针指向当前节点cur时,以倒序的方式遍历cur左子树的全部右节点;

最后调用一次printEdge(root)来完成最右侧所有节点的倒序遍历;

 1 TreeNode* reverseEdge(TreeNode *node){
 2     TreeNode *pre=nullptr;
 3     TreeNode *next=nullptr;
 4 
 5     while(node!=nullptr){
 6         next = node->right;
 7         node->right = pre;
 8         pre = node;
 9         node = next;
10     }
11 
12     return pre;
13 }
14 
15 void printEdge(TreeNode *root){
16     TreeNode *tail = reverseEdge(root);
17     TreeNode *cur = tail;
18     while(cur!=nullptr){
19         cout<<cur->val<<endl;
20         cur = cur->right;
21     }
22     reverseEdge(tail);
23 }
24 
25 void morrisPost(TreeNode *root){
26     if(root==nullptr)
27         return ;
28     TreeNode *cur=root, *mostRight=nullptr;
29 
30     while(cur!=nullptr){
31         if(cur->left!=nullptr){
32             //有左子树,寻找mostright节点
33             mostRight=cur->left;
34             //寻找左子树最右节点,注意避免回到当前节点
35             while(mostRight->right!=nullptr && mostRight->right!=cur)
36                 mostRight=mostRight->right;
37             
38             if(mostRight->right==nullptr){
39                 //若mostRight指向空,则令其指向cur,cur左移
40                 mostRight->right=cur;
41                 cur=cur->left;
42             }
43             else if(mostRight->right==cur){
44                 //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动        
45                 mostRight->right=nullptr;
46                 printEdge(cur->left);
47                 cur=cur->right;
48             }
49 
50         }
51         else{
52             //无左子树,让cur向右移动
53             cur=cur->right;
54         }
55     }
56     printEdge(root);
57 }

 

posted @ 2021-09-08 15:51  Cheung-10  阅读(22)  评论(0)    收藏  举报