Morris

Morris

/*Morris遍历树:
 *一;如果一个结点有左子树会到达此节点两次(第二次到达结点的时候左子树的所有结点都遍历完成),第一次遍历左子树最后
 *    节点为nullptr,第二次遍历指向他自己 
 *二:否则到达一次(第一次到来和第二次到来一起 ) 
 *当前节点cur 
 *1.如果cur没有左子树,cur向右移动:cur=cur->right
 *2.如果cur有左结点,找左子树最右的结点记为mostRight 
 *    1>如果mostRight的右指针为nullptr,让其指向cur,cur向左移动:cur=cur->left
 *  2>如果mostRight指向cur,让其指向nullptr,cur向右移动 
 */
#include <iostream>
#include <algorithm>
#include <iterator>
#include <list> 
using namespace std;

typedef struct Tree
{
    int value;
    Tree *left,*right;
    Tree()
    {
        value=0;
        left=right=nullptr;
    }
}Tree;
void create_tree(Tree **root)
{
    int n;
    cin>>n;
    if(n==0)
        *root=nullptr;
    else
    {
        *root=new Tree();//*root中的内容就是地址 
        (*root)->value=n;
        (*root)->left=nullptr;
        (*root)->right=nullptr;
        create_tree(&((*root)->left));
        create_tree(&((*root)->right));
    }
}
class Morris
{
    public:
        void morris_in(Tree *const root);//O(1)的空间复杂度遍历方法 
        void morris_pre(Tree *const root);
        void morris_back(Tree *const root);
    private:
        void print_edge(Tree *const cur);
};
//先序中序只是选择时机的差别 
void Morris::morris_pre(Tree *const root)
{
    if(root==nullptr)    
        return;
    
    Tree *cur=root;
    Tree *mostRight=nullptr;
    while(cur!=nullptr)//当前节点不为nullptr继续遍历 
    {
        mostRight=cur->left;
        if(mostRight!=nullptr)//第二种情况:有左结点 
        {
            //找当前节点左子树的最右结点 
            while(mostRight->right!=nullptr&&mostRight->right!=cur)
                mostRight=mostRight->right;
            
            //<1>如果不指向当前节点(也就是指向nullptr,即第一次到来),就让它指向当前节点
            if(mostRight->right!=cur)
            {
                mostRight->right=cur;
                cout<<cur->value<<" ";
                cur=cur->left;
                continue;
            }
            else//<2>如果指向当前节点(也即第二次到来)把值置为nullptr 
                mostRight->right=nullptr;
        }
        else//一个结点没有左子树,第一次到来和第二次到来一起 
            cout<<cur->value<<" ";
        //第一种情况:没有左结点向右走    
        cur=cur->right;
    }
    cout<<endl;
}

//中序打印:如果一个节点有左子树,把左子树都处理完再打印自己 
void Morris::morris_in(Tree *const root)
{
    if(root==nullptr)
        return;
    
    Tree *cur=root;
    Tree *mostRight=nullptr;
    while(cur!=nullptr)
    {
        mostRight=cur->left;
        if(mostRight!=nullptr)
        {
            while(mostRight->right!=nullptr&&mostRight->right!=cur)
                mostRight=mostRight->right;
                
            if(mostRight->right!=cur)
            {
                mostRight->right=cur;
                cur=cur->left;
                continue;
            }
            else
                mostRight->right=nullptr;
        }
        //把打印时机放在最后一次来到此节点(如果结点没左子树第一次和第二次同时到来)
        cout<<cur->value<<" ";
        
        //此节点要向右走,也就是左子树都处理完 
        cur=cur->right;
    }
    cout<<endl;
}

//把打印时机放在第二次(该结点必须两次来到)来到该结点的时候,只关注能两次到来该节点的结点
//第二次到来时逆序打印左子树的右边界,打印完成之后在整个函数退出之前单独打印整个数的右边界 
void Morris::morris_back(Tree *const root)
{
    if(root==nullptr)
        return;
        
    Tree *cur=root;
    Tree *mostRight=nullptr;
    while(cur!=nullptr)
    {
        mostRight=cur->left;
        if(mostRight!=nullptr)//有左子树 
        {
            while(mostRight->right!=nullptr&&mostRight->right!=cur)
                mostRight=mostRight->right;
                
            if(mostRight->right!=cur)
            {
                mostRight->right=cur;
                cur=cur->left;
                continue;
            }
            else//第二次来到此节点 
            {
                mostRight->right=nullptr;
                print_edge(cur->left);
            }
        }
        cur=cur->right;
    }
    print_edge(root);
    cout<<endl;
}
void Morris::print_edge(Tree *const cur)
{
    Tree *t=cur;
    list<Tree *> list;
    while(t!=nullptr)
    {
        list.push_back(t);
        t=t->right;
    }
    list.reverse();
    for(auto it=list.begin();it!=list.end();++it)
        cout<<(*it)->value<<" ";
}
int main() 
{
    Tree *root=nullptr;
    create_tree(&root);
    
    Morris ms;
    ms.morris_pre(root);
    
    ms.morris_in(root);
    
    ms.morris_back(root);
    return 0;
}

 

posted on 2019-03-16 22:52  tianzeng  阅读(271)  评论(0编辑  收藏  举报

导航