题解 | #遍历二叉树的神级方法#

遍历二叉树的神级方法

http://www.nowcoder.com/practice/5abcb95fe19d475a989dac3ba53e4635

import java.io.;
import java.util.
;

public class Main{
static class Node{
public int value;
public Node left;
public Node right;

    public Node(int data){
        this.value=data;
    }
}
/*Morris遍历
时间复杂度O(N),空间复杂度O(1)
假设当前节点为cur,初始cur就是整棵树的头节点,根据以下标准让cur移动:
1、如果cur为null,则过程停止,否则继续下面的过程
2、如果cur没有左子树,则让cur向右移动,cur=cur.right
3、如果cur有左子树,则找到cur左子树最右的节点,记为mostRight
    1)如果mostRight的right指针指向null,令mostRight.right=cur,也就是让mostRight的right指针指向当前节点
        然后cur向左移动,cur=cur.left
    2)如果mostRight的right指针指向cur,令mostRight.right=null,也就是让mostRight的right指针指向null
        然后cur向右移动,cur=cur.right
* */
public static void morris(Node head){
    //1、
    if(head==null){
        return;
    }
    Node cur=head;
    Node mostRight=null;
    while (cur!=null){
        mostRight=cur.left;
        if(mostRight!=null){    //cur有左子树
            //找到cur左子树的最右节点
            while (mostRight.right!=null&&mostRight.right!=cur){
                mostRight=mostRight.right;
            }
            //从上面while出来,mostRight就是cur左子树的最右节点
            if(mostRight.right==null){
                mostRight.right=cur;
                cur=cur.left;
                continue;//回到最外层while,继续判断cur情况
            }else {     //如果mostRight.right指向cur
                mostRight.right=null;
            }

        }
        //cur如果没有左子树,cur向右移动
        //或者cur左子树的最右节点的right指向cur,cur向右移动
        cur=cur.right;
    }

}


/*先序遍历      根 左 右
1、对于cur只能到达一次的节点(无左子树的节点),cur到达时直接打印
2、对于cur到达两次的节点(有左子树的节点),cur第一次到达时打印,第二次到达时不打印
* */
public static void morrisPre(Node head){
    if(head==null){
        return;
    }

    Node cur=head;
    Node mostRight=null;
    while (cur!=null){
        mostRight=cur.left;
        //cur有左子树
        if(mostRight!=null){
            //找出左子树的最右节点
            while (mostRight.right!=null&&mostRight.right!=cur){
                mostRight=mostRight.right;
            }
            //mostRight.right是否指向null
            if(mostRight.right==null){
                mostRight.right=cur;
                System.out.print(cur.value+" ");
                cur=cur.left;
                continue;
            }else {
                mostRight.right=null;
            }
        }else {
            System.out.print(cur.value+" ");
        }
        cur=cur.right;
    }

}


/*中序遍历      左 根 右
1、对于cur只能到达一次的节点(无左子树的节点),cur到达时直接打印
2、对于cur到达两次的节点(有左子树的节点),cur第一次到达时不打印,第二次到达时打印
* */
public static void morrisIn(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;
            }
            //左子树最右节点的right指针是否为null
            if(mostRight.right==null){
                mostRight.right=cur;
                cur=cur.left;
                continue;
            }else {
                mostRight.right=null;
            }
        }
        System.out.print(cur.value+" ");
        cur=cur.right;

    }
}


/*后序遍历      左 右 根
1、对于cur只能到达一次的节点(无左子树的节点),直接跳过
2、对于cur到达两次的节点(有左子树的节点)X,cur第一次到达X时,没有打印行为;
    第二次到达X时,逆序打印X左子树的右边界
3、cur遍历完成后,逆序打印整棵树的右边界
* */
public static void morrisPos(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;
            }
            //最右节点的right指针是否指向null
            if(mostRight.right==null){  //第一次到达
                mostRight.right=cur;
                cur=cur.left;
                continue;
            }else {                 //第二次到达
                mostRight.right=null;
                printEdge(cur.left);    //逆序打印左子树的右边界
            }

        }
        cur=cur.right;

    }
    //3、逆序打印整棵树的右边界
    printEdge(head);

}


public static void printEdge(Node head){
    Node tail=reverseEdge(head);
    Node cur=tail;
    while (cur!=null){
        System.out.print(cur.value+" ");
        cur=cur.right;
    }
    reverseEdge(tail);//再将 树逆序(恢复)
}

//逆序右边界
public static Node reverseEdge(Node from){
    Node pre=null;
    Node next=null;
    while (from!=null){
        next=from.right;
        from.right=pre;//逆序
        pre=from;
        from=next;
    }
    return pre;
}

/*
in: 3 1
    1 2 3
    2 0 0
    3 0 0
out:1 2 3
    2 1 3
    2 3 1
* */
public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    String[] input = in.nextLine().split(" ");
    int n = Integer.parseInt(input[0]);
    Node root = new Node(Integer.parseInt(input[1]));
    HashSet<Node> set = new HashSet<Node>();
    set.add(root);

    for (int i = 0; i < n; i++) {
        //build the binary tree
        String[] nodes = in.nextLine().split(" ");
        int fatherValue = Integer.parseInt(nodes[0]);
        int leftValue = Integer.parseInt(nodes[1]);
        int rightValue = Integer.parseInt(nodes[2]);
        //遍历添加
        for (Node e : set) {
            //1、比较根节点
            if (e.value == fatherValue) {
                //2、建立左右节点
                e.left = leftValue == 0 ? null : new Node(leftValue);
                e.right = rightValue == 0 ? null : new Node(rightValue);
                //3、将左右节点添加进HashSet
                if (leftValue != 0) {
                    set.add(e.left);
                }
                if (rightValue != 0) {
                    set.add(e.right);
                }
                //4、此行遍历完,该舍弃
                set.remove(e);
                break;
            }
        }
    }

    morrisPre(root);
    System.out.println();
    morrisIn(root);
    System.out.println();
    morrisPos(root);
    System.out.println();
}

}

全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务