morris遍历时二叉树遍历的一种更高效的方式。其他基础的二叉树遍历不在这里赘述。 二叉树的前中后序,层序遍历详解
morris遍历可以达到空间复杂度O(1),时间复杂度O(2n)
morris遍历过程:
- 如果cur.left == null,直接cur = cur.right
- 如果cur.left != null,就找到左子树中最右的结点,记做mostRight。
- 如果mostRight.right == cur ,则将mostRight.right = null,然后cur = cur.right
- 将mostRight.right = null, 则将mostRight.right = cur, 然后cur = cur.left
过程解释(中序为例):
- 其实是巧用叶子结点的空闲指针,来代替递归。遍历二叉树的过程是 左子树-跟结点-右子树。所以morris算法中,再遍历左子树之前,将左子树中最右的结点的right指向跟结点,就可以再遍历完左子树之后,回到跟结点。
- 回到跟结点的时候,再将那个辅助指向删除,然后再去遍历右子树即可。
- 通过过程可以知道每个节点都达到过两次(第二次是去验证并删除指向的时候)
代码:
- morris最好的实现只有前序和中序遍历。因为后序的话要回到跟结点两次。就达不到O(2n)的效果。
private static void morrisProOrder(Node head) {
if (head == null) return;
Node cur = head;
Node mostRight = null;
while (cur != null) {
System.out.print(cur.val + " ");
mostRight = cur.left;
if (mostRight != null) {
while (mostRight.right != null && mostRight.right != cur.right) {
mostRight = mostRight.right;
}
if (mostRight.right == null) {
mostRight.right = cur.right;
cur = cur.left;
continue;
} else {
mostRight.right = null;
}
}
cur = cur.right;
}
}
private static void morrisMidOrder(Node head) {
if (head == null) return;
Node cur = 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 == cur) {
mostRight.right = null;
} else {
mostRight.right = cur;
cur = cur.left;
continue;
}
}
System.out.print(cur.val + " ");
cur = cur.right;
}
}
|