Morris遍历

Morris遍历

通常,二叉树的前、中、后序遍历有两种方法。

  1. 使用递归,时间复杂度 O ( N ) O(N) O(N) 空间复杂度 O ( N ) O(N) O(N)
  2. 使用栈(stack) ,时间复杂度 O ( N ) O(N) O(N) 空间复杂度 O ( N ) O(N) O(N)

其中 N N N 代表节点数。

但是 Morris 遍历可以做到在 O ( N ) O(N) O(N) 时间 O ( 1 ) O(1) O(1) 空间对整个二叉树进行遍历。

Morris遍历流程

记录当前节点为 root

  1. 如果当前节点没有左孩子,root = root->right​
  2. 如果当前节点有左孩子,找到左节点最右的节点,记为 morris​
    1. 如果 morris 右节点为空,morris->right = root​
    2. 如果 morris 左右节点不为空,root = root->right, morris->right = nullptr

动图演示:

Morris遍历

定义二叉树

struct TreeNode {
  int val;
  TreeNode *left;
  TreeNode *right;
  TreeNode() : val(0), left(nullptr), right(nullptr) {}
  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  TreeNode(int x, TreeNode *left, TreeNode *right)
      : val(x), left(left), right(right) {}
};

Example Tree

中序遍历

void inorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;

    while (root != nullptr) {
        if (root->left != nullptr) {
            // morris 节点就是当前 root
            // 节点向左走一步,然后一直向右走至无法走为止
            morris = root->left;
            while (morris->right != nullptr && morris->right != root) {
                morris = morris->right;
            }

            // 让 morris 的右指针指向 root,继续遍历左子树
            if (morris->right == nullptr) {
                morris->right = root;
                root = root->left;
            }
            // 说明左子树已经访问完了,我们需要断开链接
            else {
                cout << root->val << " ";
                morris->right = nullptr;
                root = root->right;
            }
        }
        // 如果没有左孩子,则直接访问右孩子
        else {
            cout << root->val << " ";
            root = root->right;
        }
    }
    cout << endl;
}

前序遍历

void preorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;
    while (root) {
        if (root->left) {
            morris = root->left;
            while (morris->right && morris->right != root) {
                morris = morris->right;
            }
            if (morris->right == nullptr) {
                cout << root->val << " ";
                morris->right = root;
                root = root->left;
            } else {
                root = root->right;
                morris->right = nullptr;
            }

        } else {
            cout << root->val << " ";
            root = root->right;
        }
    }
    cout << endl;
}

后序遍历

void print(TreeNode *root) {
    TreeNode *tail = reverse(root);
    TreeNode *cur = tail;
    while (cur) {
        cout << cur->val << " ";
        cur = cur->right;
    }
    reverse(tail);
}

TreeNode *reverse(TreeNode *node) {
    TreeNode *pre = nullptr;
    TreeNode *next = nullptr;
    while (node != nullptr) {
        next = node->right;
        node->right = pre;
        pre = node;
        node = next;
    }
    return pre;
}

void postorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;
    TreeNode *head = root;
    while (root) {
        if (root->left) {
            morris = root->left;
            while (morris->right && morris->right != root) {
                morris = morris->right;
            }
            if (morris->right == nullptr) {
                morris->right = root;
                root = root->left;
            } else {
                morris->right = nullptr;
                print(root->left);
                root = root->right;
            }
        } else {
            root = root->right;
        }
    }
    print(head);
}

测试

#include <algorithm>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;

struct TreeNode {
  int val;
  TreeNode *left;
  TreeNode *right;
  TreeNode() : val(0), left(nullptr), right(nullptr) {}
  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  TreeNode(int x, TreeNode *left, TreeNode *right)
      : val(x), left(left), right(right) {}
};

class Solution {
 private:
  void print(TreeNode *root) {
    TreeNode *tail = reverse(root);
    TreeNode *cur = tail;
    while (cur) {
      cout << cur->val << " ";
      cur = cur->right;
    }
    reverse(tail);
  }
  TreeNode *reverse(TreeNode *node) {
    TreeNode *pre = nullptr;
    TreeNode *next = nullptr;
    while (node != nullptr) {
      next = node->right;
      node->right = pre;
      pre = node;
      node = next;
    }
    return pre;
  }

 public:
  void inorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;

    while (root != nullptr) {
      if (root->left != nullptr) {
        // morris 节点就是当前 root
        // 节点向左走一步,然后一直向右走至无法走为止
        morris = root->left;
        while (morris->right != nullptr && morris->right != root) {
          morris = morris->right;
        }

        // 让 morris 的右指针指向 root,继续遍历左子树
        if (morris->right == nullptr) {
          morris->right = root;
          root = root->left;
        }
        // 说明左子树已经访问完了,我们需要断开链接
        else {
          cout << root->val << " ";
          morris->right = nullptr;
          root = root->right;
        }
      }
      // 如果没有左孩子,则直接访问右孩子
      else {
        cout << root->val << " ";
        root = root->right;
      }
    }
    cout << endl;
  }

  void preorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;
    while (root) {
      if (root->left) {
        morris = root->left;
        while (morris->right && morris->right != root) {
          morris = morris->right;
        }
        if (morris->right == nullptr) {
          cout << root->val << " ";
          morris->right = root;
          root = root->left;
        } else {
          root = root->right;
          morris->right = nullptr;
        }

      } else {
        cout << root->val << " ";
        root = root->right;
      }
    }
    cout << endl;
  }

  void postorderTraversal(TreeNode *root) {
    TreeNode *morris = nullptr;
    TreeNode *head = root;
    while (root) {
      if (root->left) {
        morris = root->left;
        while (morris->right && morris->right != root) {
          morris = morris->right;
        }
        if (morris->right == nullptr) {
          morris->right = root;
          root = root->left;
        } else {
          morris->right = nullptr;
          print(root->left);
          root = root->right;
        }
      } else {
        root = root->right;
      }
    }
    print(head);
  }
};

int main() {
  Solution s;
  TreeNode *root = new TreeNode(1);
  root->left = new TreeNode(2);
  root->right = new TreeNode(3);

  root->left->left = new TreeNode(4);
  root->left->right = new TreeNode(5);

  cout << "中序遍历: " << endl;
  s.inorderTraversal(root);
  cout << "前序遍历: " << endl;
  s.preorderTraversal(root);
  cout << "后序遍历: " << endl;
  s.postorderTraversal(root);
  return 0;
}

中序遍历:

4 2 5 1 3

前序遍历:

1 2 4 5 3

后序遍历:

4 5 2 3 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值