二叉树遍历

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;
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值