# Morris traversal

Morris traversal is used to save space when traversing binary trees
If it is a conventional binary tree traversal, whether it is implemented recursively or iteratively, the space complexity is O(M), M is the height of the tree, because each node will return to it three times, the difference in the order of traversal is here Which of the three visits to this node

// the first time
process(node.left)
// the second time
process(node.right)
// the third time

Therefore, there is a need to store the current node, and pop it from the stack when returning to the current node
How many nodes will be pushed into the stack, and the height of the tree determines Morris traversal is a space-complex optimization of binary tree traversal.

# Details of the Morris Traversal

Morris traversal is to use the free right pointer of the node in the tree

Suppose you come to the current node cur, at the beginning cur comes to the position of the head node
1) If cur has no left child, cur moves to the right (cur = cur.right)
2) If cur has a left child, find the rightmost node mostRight on the left subtree
a. If the right pointer of mostRight points to null, let it point to cur, and then move cur to the left (cur = cur.left)
b. If the right pointer of mostRight points to cur, let it point to null, then cur moves to the right (cur = cur.right)
3) When cur is empty, the traversal stops In fact, it uses the right pointer state of the rightmost node of the left subtree of the current node to mark how many times it has come to the current node
If the right pointer of the rightmost node of the left subtree of the current node is null, it means that it is the first time to come to the current node
If the right pointer of the rightmost node of the left subtree of the current node points to the current node, it means that it has been here once before, and now it is the second time to come to the current node

# Morris traversal code implementation

```    /**
* Morris sequence
*/
public static void process(Node head) {
Node cur = head; // The cur pointer, initially at the head node
Node mostRight = null; // the rightmost node of the left subtree
while (cur != null) {
mostRight = cur.left; // left tree
if (mostRight != null) { // left tree is not empty
// go right
while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right;
// The right pointer of the rightmost node of the left subtree is empty, the first time
if (mostRight.right == null) {
// Point to the current node, then move cur to the left
mostRight.right = cur;
cur = cur.left;
continue;
} else {
// The right pointer of the rightmost node of the left subtree is not empty. For the second time, set the right pointer of mosrtRight to empty
mostRight.right = null;
}
}
// cur pointer to the right
cur = cur.right;
}
}
```

# Morris preorder traversal

```    /**
* Morris preorder traversal
*/
public static void processPre(Node head) {
Node mostRight = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right;
if (mostRight.right == null) {
mostRight.right = cur;
// The node with the left tree will be printed when it comes for the first time
System.out.println(cur.value);
cur = cur.left;
continue;
} else {
mostRight.right = null;
}
} else {
// There is no node in the left tree, directly print
System.out.println(cur.value);
}
cur = cur.right;
}
}
```

# Morris inorder traversal

```    /**
* Morris Inorder traversal
*/
public static void processIn(Node head) {
Node mostRight = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right;
if (mostRight.right == null) {
mostRight.right = cur;
cur = cur.left;
continue;
} else {
mostRight.right = null;
}
}
// Regardless of whether there is a left tree or not, they will come here, and those who have a left tree will come here for the second time
System.out.println(cur.value);
cur = cur.right;
}
}
```

# Morris post-order traversal

```    /**
* Morris Subsequent traversal
*/
public static void processPost(Node head) {
Node mostRight = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right;
if (mostRight.right == null) {
mostRight.right = cur;
cur = cur.left;
continue;
} else {
mostRight.right = null;
//Each time the node is returned for the second time, print the right edge of its left tree, in reverse order
printEdge(cur.left);
}
}
cur = cur.right;
}
//Finally, print the right boundary of the entire tree in reverse order
}

// Print the right edge of the tree in reverse order
private static void printEdge(Node head) {
// right boundary of tree, linked list reversed
Node cur = tail;
// Traverse the linked list to print
while (cur != null) {
System.out.println(cur.value);
cur = cur.right;
}
reverse(tail);
}

// Reverse the right-bound list of a tree
private static Node reverse(Node head) {
Node pre = null;
Node right = null;
while (cur != null) {
right = cur.right;
cur.right = pre;
pre = cur;
cur = right;
}
return pre;
}
```

# Morris traversal to determine whether a tree is a search binary tree

```/**
* Morris Traverse to determine whether a tree is a search binary tree
* Created by huangjunyi on 2022/9/10.
*/
public class Morris02 {

private static class Node {
Node left;
Node right;
int value;
}

public static boolean isBST(Node head) {
if (head == null) return true;
Node mostRight = null;
//Take a variable preValue to record the value of the node traversed before
Integer preValue = null;
while (cur != null) {
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right;
if (mostRight.right == null) {
mostRight.right = cur;
cur = cur.left;
continue;
} else {
mostRight.right = null;
}
}
// In the order of Morris in-order traversal, judge whether the value of the previous node is greater than the current node, if yes, return false, indicating that it is not a BST
// Here, I don’t care if the pointer of the tree is changed and messed up, all return false directly, otherwise it cannot return false directly, and return after traversing
if (preValue != null && cur.value <= preValue) return false;
preValue = cur.value;
cur = cur.right;
}
return true;
}

}
```

# Morris traverses to find the height of the leaf node closest to the head node of a tree

```/**
* Morris Traverse to find the height of the leaf node closest to the head node in a tree
* Created by huangjunyi on 2022/9/10.
*/
public class Morris03 {

private static class Node {
Node left;
Node right;
int value;
}

public static int getMinHigh(Node head) {
if (head == null) return 0;
Node mostRight = null;
int minHigh = Integer.MAX_VALUE;
int leftRightBoardsize = -1;
int curLevel = 0; // current node level
while (cur != null) {
mostRight = cur.left;
leftRightBoardsize = 1;
if (mostRight != null) {
//current node has left tree
while (mostRight.right != null && mostRight.right != cur) {
// Find the rightmost node of the left tree of the current node while recording the number of nodes at the right boundary of the left tree
mostRight = mostRight.right;
leftRightBoardsize++;
}
if (mostRight.right == null) {
// Entering here means coming to the current node for the first time
// Modify the right pointer of the rightmost node of the left tree to point to the current node, and move the cur pointer to the left node
mostRight.right = cur;
curLevel++;
cur = cur.left;
continue;
} else {
// Entering here means coming to the current node for the second time
// See if the left node of the rightmost node of the left subtree of the current node is empty, which means it is a leaf node
// It is found that the rightmost node of the left tree is a child node, clear it, and update minHigh
if (mostRight.left == null) {
minHigh = Math.min(minHigh, curLevel);
}
// curLevel is currently the height of the rightmost node of the left tree. Subtract the number of nodes at the right border of the left tree from leftRightBoardsize to obtain the height of the current node
curLevel -= leftRightBoardsize;
// Restores the right pointer of the rightmost node of the current node's left subtree
mostRight.right = null;
}
} else {
//The current node does not have a left tree, only the number of layers ++
curLevel++;
}
cur = cur.right;
}
return minHigh;
}

}
```

# When to Traverse with Morris

Don’t use it in the written test, just use the most common and best recursion
During the interview, you can use Morris traversal to optimize

If the answers of the left and right subtrees are strictly required to integrate the answers of the current node, then only recursion can be used instead of Morris traversal
If it is not strictly dependent on the answers of the left and right subtrees, it can be optimized with Morris traversal

Posted by bran on Mon, 05 Dec 2022 21:41:45 +0530