morris遍历二叉树, 做到消耗空间为o(1):
思路: 当前结点cur
[1] 如果当前结点没有左孩子, cur = cur -> right;
[2] 如果当前结点有左孩子, 找到左子树的最右结点 mostRight, 如果
[2.1] mostRight.right == cur, 这表示当前是第二次访问cur结点, 表示cur的左子树全部遍历完毕. 接着遍历右子树
[2.2] mostRight.right == null, 表示当前是第一次访问 cur 结点, 正在做线索,利用mostRight存储cur , 遍历完左子树后, 才能返回cur.
用morris遍历二叉树, 前序遍历和中序遍历都比较好实现,
[1] 前序遍历 在 [1] 和 [2.2]时打印
[2] 中序遍历 在[1] 和 [2.1]时打印
[3] 后序遍历由于 morris 算法本身是不会到结点第三次的, 所以没办法直接打印出来. 需要这样做:
当前是第二次遍历到cur时, 此时cur的左边已经遍历完成. 这时候我们 逆序 遍历cur 左子树的 "右边界 ", 如果是开一个栈的话还好说, 但是不要求开空间的话, 就需要一点小技巧: 先让每一个结点的右孩子指向原本自己的父节点, 开头的父节点指向Null, 遍历时从最后一个结点开始遍历, 他需要将自己的right指回原来的样子, 恢复指针的过程就打印完了.... <点赞>!!!
以下是后序遍历代码:
public void morrisInPost() {
if (this.root == null) {
return;
}
Node node = this.root;
Node mostRight = null;
while (node != null) {
if (node.left != null) {
mostRight = node.left;
while (mostRight.right != null && mostRight.right != node) {
mostRight = mostRight.right;
}
if (mostRight.right == null) {
mostRight.right = node;
node = node.left;
} else {
mostRight.right = null;
// 逆序打印左子树的右边界
printEdge(node.left);
node = node.right;
}
} else {
node = node.right;
}
}
// 逆序打印整棵树的右边界
printEdge(root);
System.out.println();
}
private void printEdge(Node node) {
Node parent = null;
while (node != null) {
Node next = node.right;
node.right = parent;
parent = node;
node = next;
}
// 开始打印
Node trueNext = null;
while (parent != null) {
Node next = parent.right;
parent.right = trueNext;
trueNext = parent;
System.out.print("<" + parent + "> ");
parent = next;
}
}