a. 若前驱结点的右孩子为空,则将前驱结点的右孩子指向当前结点,当前结点更新为当前结点的左孩子;进入3;
b. 若前驱结点的右孩子为当前结点(不为空),将前驱结点的右孩子置NULL,输出当前结点,当前结点更新为当前结点的右孩子,进入3;
若当前结点不为空,进入1;否则程序结束;
伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
cur = root repeat until cur != NULL: if cur.left != NULL: pre = cur.left; while pre.right == NULL && pre.right != cur://找到前驱结点pre pre = pre.right if pre.right == NULL: pre.right = cur cur = cur.left else: print(cur) pre.right = NULL cur = cur.right else: print(cur) cur = cur.right
publicstaticvoidinOrder(TreeNode root) { TreeNodecur= root, pre = null; for (; cur != null;) { if (cur.left != null) { pre = cur.left; // find predecessor while (pre.right != null && pre.right != cur) pre = pre.right; if (pre.right == null) {// create thread pre.right = cur; cur = cur.left; } else { print(cur); pre.right = null; cur = cur.right; } } else { print(cur); cur = cur.right; } } }
3. Morris 前序遍历
对于前序遍历,只需要在中序遍历的基础上稍加修改便可以完成。
Morris 前序遍历的流程如下:
当前结点的左孩子是否为空,若是则输出当前结点,并更新当前结点为当前结点的右孩子;否则进入2;
在当前结点的左子树中寻找中序遍历下的前驱结点(左子树中最右结点)
a. 若前驱结点的右孩子为空,则将前驱结点的右孩子指向当前结点,输出当前结点(在这里输出,和中序遍历不同的地方),当前结点更新为当前结点的左孩子;进入3;
b. 若前驱结点的右孩子为当前结点(不为空),将前驱结点的右孩子置NULL,当前结点更新为当前结点的右孩子,进入3;
若当前结点不为空,进入1;否则程序结束;
伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
cur = root; repeat until cur != NULL: if cur.left != NULL: pre = cur.left; while pre.right == NULL && pre.right != cur://找到前驱结点pre pre = pre.right if pre.right == NULL: pre.right = cur print(cur)//此处和中序遍历不同 cur = cur.left else: pre.right = NULL cur = cur.right else: print(cur) cur = cur.right
publicstaticvoidpreOrder(TreeNode root) { TreeNodecur= root, pre = null; for (;cur != null;) { if (cur.left != null) { pre = cur.left; // find predecessor while (pre.right != null && pre.right != cur) pre = pre.right; if (pre.right == null) {// create thread print(cur);// print node here pre.right = cur; cur = cur.left; } else { pre.right = null;//delete thread cur = cur.right; } } else { print(cur); cur = cur.right; } } }
4. Morris 后序遍历
后序遍历的流程如下:
新建一个Dummy结点,该结点的左孩子指向树根root,将Dummy作为当前结点;
当前结点的左孩子是否为空,更新当前结点为当前结点的右孩子;否则进入2;
在当前结点的左子树中寻找中序遍历下的前驱结点(左子树中最右结点):
a. 若前驱结点的右孩子为空,则将前驱结点的右孩子指向当前结点,当前结点更新为当前结点的左孩子,进入3;
b. 若前驱结点的右孩子为当前结点(不为空),反转当前结点到前驱结点之间的路径,输出该路径所有结点;反转当前结点到前驱结点之间的路径,恢复原状。将前驱结点的右孩子置NULL,当前结点更新为当前结点的右孩子,进入3;
若当前结点不为空,进入1;否则程序结束;
伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
dummy = Node(-1) dummy.left = root cur = dummy repeat until cur != NULL: if cur.left != NULL: pre = cur.left; while pre.right == NULL && pre.right != cur://找到前驱结点pre pre = pre.right if pre.right == NULL: pre.right = cur cur = cur.left else: reverse(cur.left, pre) print(pre, cur.left) reverse(pre, cur.left)//再次反转,恢复原状 pre.right = NULL cur = cur.right else: cur = cur.right