Java的Morris前中后序遍历

 ↑↑↑↑↑全文使用的示例二叉树↑↑↑↑↑

首先要搞懂的几个概念:

1.前驱节点和后继节点:

        即打印顺序的前一个和后一个,例如打印出来是:4 2 6 5 7 1 3 

        对于2,前驱节点就是4,后继节点就是6

        除了4,其余每一个节点都有前驱节点。除了3,其余每一个节点都有后继驱节点

2.线索二叉树

        在二叉树的基础上增加线索,所谓线索就是加上前驱节点或者后继节点或者都加上。

Morris前序 (前中后总的代码在最后

public class alg3132morrisPreMid {
    public static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode() {}
        public TreeNode(int val) { this.val = val; }
        public TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }
    public static void main(String[] args) {
        TreeNode node7 = new TreeNode(7,null,null);
        TreeNode node6 = new TreeNode(6,null,null);
        TreeNode node5 = new TreeNode(5, node6, node7);
        TreeNode node4 = new TreeNode(4, null, null);
        TreeNode node3 = new TreeNode(3, null, null);
        TreeNode node2 = new TreeNode(2, node4, node5);
        TreeNode node1 = new TreeNode(1, node2, node3);

        morrisPre(node1);
    }

    private static void morrisPre(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;//建立线索指针
                    System.out.print(cur.val+" ");//输出有左子树的节点
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                }
            }else {//cur节点没有左子树
                System.out.print(cur.val+" ");//输出没有左子树的节点
            }
            cur = cur.right;
        }
    }
}

总的打印步骤(根左右):

cur为1 ,找到7,建立线索7->1 并打印 cur           输出为1

cur为2 ,找到4,建立线索4->2 并打印 cur           输出为1 2

cur为4 ,没有左子树,直接打印cur                      输出为1 2 4

cur为2 ,找到4,删除线索4->2 ,cur = cur.right 

cur为5 , 找到6,建立线索6->5,并打印 cur       输出为1 2 4 5

cur为6 ,没有左子树,直接打印cur                      输出为1 2 4 5 6

cur为5 ,找到6,删除线索6->5 ,cur = cur.right 

cur为7 ,没有左子树,直接打印cur                      输出为1 2 4 5 6 7

cur为1,找到7,删除线索7->1 ,cur = cur.righ

cur为3 ,没有左子树,直接打印cur                      输出为1 2 4 5 6 7 3

Morris中序

private static void morrisMid(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                }
            }
            System.out.print(cur.val+" ");
            cur = cur.right;
        }
    }

与前序唯一唯一的区别只有System.out.print()语句的位置,

只有删除线索或者判断cur节点左子树为空才执行到打印语句

总的打印步骤(左根右):

cur为1 ,找到7,建立线索7->1        continue

cur为2 ,找到4,建立线索4->2        continue

cur为4 ,没有左子树,打印cur                                     输出为4

cur为2 ,找到4,删除线索4->2 ,打印cur                    输出为4 2

cur为5 , 找到6,建立线索6->5        continue

cur为6 ,没有左子树,打印cur                                     输出为4 2 6

cur为5 ,找到6,删除线索6->5 ,打印cur                   输出为4 2 6 5

cur为7 ,没有左子树,打印cur                                     输出为4 2 6 5 7

cur为1,找到7,删除线索7->1 ,打印cur                     输出为4 2 6 5 7 1

cur为3 ,没有左子树,打印cur                                      输出为4 2 6 5 7 1 3

Morris后序

private static void morrisPost(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode root = cur;
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                    printNode(cur.left);
                }
            }
            cur = cur.right;
        }
        printNode(root);
    }

    private static void printNode(TreeNode head) {
        TreeNode tail = reverse(head);
        while (tail != null){
            System.out.print(tail.val + " ");
            tail = tail.right;
        }
        reverse(tail);//翻转第一次后破坏了二叉树的结构,所以要翻回去
    }

    private static TreeNode reverse(TreeNode node) {//链表翻转代码
        if(node == null){
            return null;
        }
        TreeNode pre = null, cur, next;
        cur = node;
        while(cur != null){
            next = cur.right;
            cur.right = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

与Mid区别在打印的语句变成了打印的方法printNode(),并且保留了全树的根节点--root

总的打印步骤(左右根):

cur为1 ,找到7,建立线索7->1        continue

cur为2 ,找到4,建立线索4->2        continue

cur为4 ,没有左子树                        continue

cur为2 ,找到4,删除线索4->2 ,printNode(cur.left);      输出4

cur为5 , 找到6,建立线索6->5        continue

cur为6 ,没有左子树                        continue

cur为5 ,找到6,删除线索6->5 ,printNode(cur.left);    输出为 4 6

cur为7 ,没有左子树                        continue

cur为1,找到7,删除线索7->1 ,printNode(cur.left);      输出为4 6 7 5 2

cur为3 ,没有左子树,跳出while

printNode(root);                                                                输出为4 6 7 5 2 3 1

总代码

public class alg31_33morris {
    public static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode() {}
        public TreeNode(int val) { this.val = val; }
        public TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }
    public static void main(String[] args) {
        TreeNode node7 = new TreeNode(7,null,null);
        TreeNode node6 = new TreeNode(6,null,null);
        TreeNode node5 = new TreeNode(5, node6, node7);
        TreeNode node4 = new TreeNode(4, null, null);
        TreeNode node3 = new TreeNode(3, null, null);
        TreeNode node2 = new TreeNode(2, node4, node5);
        TreeNode node1 = new TreeNode(1, node2, node3);

        morrisPre(node1);
        System.out.println();
        morrisMid(node1);
        System.out.println();
        morrisPost(node1);
    }

    private static void morrisPre(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;//建立线索指针
                    System.out.print(cur.val+" ");//输出有左子树的节点
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                }
            }else {//cur节点没有左子树
                System.out.print(cur.val+" ");//输出没有左子树的节点
            }
            cur = cur.right;
        }
    }

    private static void morrisMid(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                }
            }
            System.out.print(cur.val+" ");
            cur = cur.right;
        }
    }

    private static void morrisPost(TreeNode cur) {
        if(cur == null){
            return;
        }
        TreeNode root = cur;
        TreeNode mostRight = null;//当前节点左子树的最右节点
        while (cur != null){
            mostRight = cur.left;//mostRight变成当前节点的左节点
            if(mostRight != null){//mostRight不为空,即cur节点有左子树
                while(mostRight.right != null && mostRight.right != cur){//找到cur节点左子树的最右节点
                    mostRight = mostRight.right;
                }
                if(mostRight.right == null){//建立线索指针
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                }else {//mostRight.right == cur 删除线索指针
                    mostRight.right = null;
                    printNode(cur.left);
                }
            }
            cur = cur.right;
        }
        printNode(root);
    }

    private static void printNode(TreeNode head) {
        TreeNode tail = reverse(head);
        while (tail != null){
            System.out.print(tail.val + " ");
            tail = tail.right;
        }
        reverse(tail);//翻转第一次后破坏了二叉树的结构,所以要翻回去
    }

    private static TreeNode reverse(TreeNode node) {//链表翻转代码
        if(node == null){
            return null;
        }
        TreeNode pre = null, cur, next;
        cur = node;
        while(cur != null){
            next = cur.right;
            cur.right = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值