Morris前序、中序、后序遍历

Morris前序遍历

算法过程

1.如果cur无左孩子,cur向右移动(cur=cur.right)
2.如果cur有左孩子,找到cur左子树上最右的节点,记为mostright

1.如果mostright的right指针指向空,让其指向cur,cur向左移动(cur=cur.left)
2.如果mostright的right指针指向cur,让其指向空,cur向右移动(cur=cur.right)

代码

#include<iostream>
#include<vector>
#include<queue>
#include <ctime>
using namespace std;

struct TreeNode
{
    int val=0;
    TreeNode *left=NULL;
    TreeNode *right=NULL;
};

void createTreeNode(TreeNode *root,int Num) {
    queue<TreeNode *> Q;
    Q.push(root);
    int data=1;
    while(data<Num){
        TreeNode *curr_node =Q.front();
        Q.pop();
        curr_node->left=new TreeNode;
        curr_node->left->val=data++;
        Q.push(curr_node->left);

        curr_node->right=new TreeNode;
        curr_node->right->val=data++;
        Q.push(curr_node->right);
    }
}

// 所有的代码都需要写在 Algo 类内,自行定义其他需要的变量或函数
class Algo
{
public:
    Algo()
    {
        cout << "algo ok" << endl;
    }

void morrisPos(TreeNode*head)//后序遍历
    {
        if (head == NULL)
            return;
        TreeNode *cur = head;
        TreeNode *pre = NULL;
        while (cur != NULL)
        {
            pre = cur->left;
            if (pre != NULL)
            {
                while (pre->right != NULL && pre->right != cur)
                    pre = pre->right;//左子树的最右结点
                if (pre->right == NULL)//第一次到达左子树的最右子树
                {
                    pre->right = cur;
                    cur = cur->left;
                    continue;
                }
                else    //第二次到达左子树的最右子树 pre->right == cur
                {
                    pre->right = NULL;
                    prnode(cur->left);//逆序打印左子树的右边界
                }
            }
            cur = cur->right;
        }
        prnode(head);
        cout<<endl;
    }

    void  prnode(TreeNode *head)//逆序打印左孩子的右边界
    {
        TreeNode *tail=renode(head);
        while(tail!=NULL){
            cout<<tail->val<<" ";
            tail=tail->right;
        }
        renode(tail);
    }

    TreeNode*renode(TreeNode*head)//右孩子指向上一个节点
    {
        TreeNode*pre=NULL;
        TreeNode*next =NULL;
        while (head != NULL)
        {
        next = head->right;
        head->right = pre;
        pre = head;
        head = next;
    }
    return pre;
    }

    int run(TreeNode *head)
    {
        //在此写入你的代码
        preorderTree(head); //普通前序遍历方法示例
        class Solution{
public:
    vector<int> preorderTraversal(TreeNode* root){
        vector<int> res;
        if(root==nullptr)
        return res;
        TreeNode* cur=root, *pre=nullptr;
        while(cur!=nullptr){
            if(cur->left==nullptr){//当前节点左子树为空则遍历右子树
                res.push_back(cur->val);
                cur=cur->right;
            }//当到达最左节点时,也是用此回退。
            else{
                pre=cur->left;//前驱节点
                while(pre->right!=nullptr && pre->right!=cur){
                    pre=pre->right;
                }//找到前驱节点的最右节点
                if(pre->right==nullptr){
                    pre->right=cur;
                    res.push_back(cur->val);
                    cur=cur->left;
                }//遍历左节点
                if(pre->right==cur){
                    pre->right=nullptr;
                    cur=cur->right;
                }//遍历右节点
            }
        }
        return res;
    }
};

        return 0; //修改为返回正确的结果
    }
    void preorderTree(TreeNode *Node)
    {
        if (Node != NULL)
        {
            cout << Node->val << endl;
            preorderTree(Node->left);
            preorderTree(Node->right);
        }
    }
};
int main()
{
    Algo algo;
    TreeNode head;
    createTreeNode(&head,10);    // 10为生成的二叉树结点的数量,根据需要自行调整
    time_t start = clock();
    algo.run(&head);
    time_t end = clock();
    cout << "程序耗时: " << double(end - start) / CLOCKS_PER_SEC << " ms" << endl;
    cout << "占用内存:" << sizeof(algo) << " byte" << endl;
    return 0;
}

Morris中序遍历

算法过程

中序遍历和前序遍历基本相同,就是输出的值的位置有点不同

代码

#include<iostream>
#include<vector>
#include<queue>
#include <ctime>
using namespace std;

struct TreeNode
{
    int val=0;
    TreeNode *left=NULL;
    TreeNode *right=NULL;
};

void createTreeNode(TreeNode *root,int Num) {
    queue<TreeNode *> Q;
    Q.push(root);
    int data=1;
    while(data<Num){
        TreeNode *curr_node =Q.front();
        Q.pop();
        curr_node->left=new TreeNode;
        curr_node->left->val=data++;
        Q.push(curr_node->left);

        curr_node->right=new TreeNode;
        curr_node->right->val=data++;
        Q.push(curr_node->right);
    }
}

// 所有的代码都需要写在 Algo 类内,自行定义其他需要的变量或函数
class Algo
{
public:
    Algo()
    {
        cout << "algo ok" << endl;
    }

void morrisIn(TreeNode *head)
    {
        if (head == NULL)
            return;
        TreeNode *cur = head;
        TreeNode *pre = NULL;
        while (cur != NULL)
        {
            pre = cur->left;
            if (pre != NULL)
            {
                while (pre->right != NULL && pre->right != cur)
                    pre = pre->right;//左子树的最右结点
                if (pre->right == NULL)
                {
                    pre->right = cur;
                    cur = cur->left;
                    continue;
                }
                else
                {
                    pre->right = NULL;
                }
            }
            cout << cur->val << " ";
            cur = cur->right;
        }
        cout << endl;
    }

    int run(TreeNode *head)
    {
        //在此写入你的代码
        preorderTree(head); //普通前序遍历方法示例
        morrisIn(head);
        return 0; //修改为返回正确的结果
    }
    void preorderTree(TreeNode *Node)
    {
        if (Node != NULL)
        {
            cout << Node->val << endl;
            preorderTree(Node->left);
            preorderTree(Node->right);
        }
    }
};

int main()
{
    Algo algo;
    TreeNode head;
    createTreeNode(&head,10);    // 10为生成的二叉树结点的数量,根据需要自行调整
    time_t start = clock();
    algo.run(&head);
    time_t end = clock();
    cout << "程序耗时: " << double(end - start) / CLOCKS_PER_SEC << " ms" << endl;
    cout << "占用内存:" << sizeof(algo) << " byte" << endl;
    return 0;
}

结果

在这里插入图片描述

Morris后序遍历

算法过程

后序遍历的顺序是左右中,想通过之前这样一个一个直接有cur指针遍历过去可不行了,但可以通过回退倒上一层把下一个左节点的右边节点一次全遍历过去再将结果翻转,因为回退到上一层节点意味着你这一层已经走过了一遍了。

代码

#include<iostream>
#include<vector>
#include<queue>
#include <ctime>
using namespace std;

struct TreeNode
{
    int val=0;
    TreeNode *left=NULL;
    TreeNode *right=NULL;
};

void createTreeNode(TreeNode *root,int Num) {
    queue<TreeNode *> Q;
    Q.push(root);
    int data=1;
    while(data<Num){
        TreeNode *curr_node =Q.front();
        Q.pop();
        curr_node->left=new TreeNode;
        curr_node->left->val=data++;
        Q.push(curr_node->left);

        curr_node->right=new TreeNode;
        curr_node->right->val=data++;
        Q.push(curr_node->right);
    }
}

// 所有的代码都需要写在 Algo 类内,自行定义其他需要的变量或函数
class Algo
{
public:
    Algo()
    {
        cout << "algo ok" << endl;
    }

void morrisPos(TreeNode*head)//后序遍历
    {
        if (head == NULL)
            return;
        TreeNode *cur = head;
        TreeNode *pre = NULL;
        while (cur != NULL)
        {
            pre = cur->left;
            if (pre != NULL)
            {
                while (pre->right != NULL && pre->right != cur)
                    pre = pre->right;//左子树的最右结点
                if (pre->right == NULL)//第一次到达左子树的最右子树
                {
                    pre->right = cur;
                    cur = cur->left;
                    continue;
                }
                else    //第二次到达左子树的最右子树 pre->right == cur
                {
                    pre->right = NULL;
                    prnode(cur->left);//逆序打印左子树的右边界
                }
            }
            cur = cur->right;
        }
        prnode(head);
        cout<<endl;
    }

    void  prnode(TreeNode *head)//逆序打印左孩子的右边界
    {
        TreeNode *tail=renode(head);
        while(tail!=NULL){
            cout<<tail->val<<" ";
            tail=tail->right;
        }
        renode(tail);
    }

    TreeNode*renode(TreeNode*head)//右孩子指向上一个节点
    {
        TreeNode*pre=NULL;
        TreeNode*next =NULL;
        while (head != NULL)
        {
        next = head->right;
        head->right = pre;
        pre = head;
        head = next;
    }
    return pre;
    }

    int run(TreeNode *head)
    {
        //在此写入你的代码
         //普通前序遍历方法示例
        morrisPos(head);
        return 0; //修改为返回正确的结果
    }
    void preorderTree(TreeNode *Node)
    {
        if (Node != NULL)
        {
            cout << Node->val << endl;
            preorderTree(Node->left);
            preorderTree(Node->right);
        }
    }
};

int main()
{
    Algo algo;
    TreeNode head;
    createTreeNode(&head,10);    // 10为生成的二叉树结点的数量,根据需要自行调整
    time_t start = clock();
    algo.run(&head);
    time_t end = clock();
    cout << "程序耗时: " << double(end - start) / CLOCKS_PER_SEC << " ms" << endl;
    cout << "占用内存:" << sizeof(algo) << " byte" << endl;
    return 0;
}

结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我老伯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值