Morris遍历
通常,二叉树的前、中、后序遍历有两种方法。
- 使用递归,时间复杂度 O ( N ) O(N) O(N) 空间复杂度 O ( N ) O(N) O(N)
- 使用栈(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
- 如果当前节点没有左孩子,
root = root->right
- 如果当前节点有左孩子,找到左节点最右的节点,记为
morris
- 如果
morris
右节点为空,morris->right = root
- 如果
morris
左右节点不为空,root = root->right, morris->right = nullptr
- 如果
动图演示:
定义二叉树
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) {}
};
中序遍历
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