• 二叉树的构造及遍历


      二叉树是一种特殊的树形结构,每个节点最多有两个子节点,两个节点有左右之分,次序不能颠倒。一般使用递归来定义二叉树,因此与二叉树相关的问题都可以通过递归来解决,二叉树节点的定义如下: 

     1 class Node{
     2     public int value=-1;
     3     public Node leftNode;
     4     public Node rightNode;
     5     public Node(int val){
     6         value=val;
     7     }
     8     public Node(){
     9         this(null); 
    10     }
    11 }
    View Code

     接下来介绍根据已知的二叉树结构,构造二叉树的方法。首先给出两个二叉树的结构,如下图所示:

    1)根据已有的二叉树结构,生成节点数组,依据节点数组构造二叉树时。约定输入的正数表示其节点编号,负数表示节点不存在。从根节点开始,构造其左子树,如果此树上还有左子树,继续操作,直至没有左子树,然后构造右子树。以A为例说明生成节点数组的过程,设节点数组为nodeArr。首先访问根节点1(nodeArr=[1]),有左子树且根节点为2(nodeArr=[1,2]),以2为根节点继续访问,仍然有左子树且根节点为4(nodeArr=[1,2,4]),继续访问,没有左子树(nodeArr=[1,2,4,-1]),也没有右子树(nodeArr=[1,2,4,-1,-1]),返回到上层,访问2的右子树,且右子树根节点为5(nodeArr=[1,2,4,-1,-1,5]),发现5没有左节点和右节点(nodeArr=[1,2,4,-1,-1,5,-1,-1]),依此类推,最终A的节点数组为nodeArr=[1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1]。同理,设B的节点数组为nodeArr2,有nodeArr2=[1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1]。

    2)根据节点数组,生成二叉树,代码如下:

     1 public class traversal {
     2     static int step=0;
     3     public static void main(String[] args){
     4         int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
     5         int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
     6         Node root=new Node();
     7         root=createBinaryTree(root,nodeArray2);
     8         System.out.println("end");
     9     }
    10     public static Node createBinaryTree(Node root,int[] nodeArray ){
    11         int val=-1;
    12         try {
    13             val = nodeArray[step];
    14             step++;
    15         }
    16         catch (ArrayIndexOutOfBoundsException ex){
    17             System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
    18         }
    19         if(val<0){
    20             System.out.println("leaf node");
    21             root=null;
    22             return root;
    23         }
    24         root=new Node(val);///指向新对象
    25         //step++;
    26         root.leftNode=createBinaryTree(root.leftNode,nodeArray);
    27         root.rightNode=createBinaryTree(root.rightNode,nodeArray);
    28         return root;
    29     }
    30 }
    31 class Node{
    32     public int value=-1;
    33     public Node leftNode;
    34     public Node rightNode;
    35     public Node(int val){
    36         value=val;
    37     }
    38     public Node(){
    39     }
    40 }
    View Code

    3)结果如下所示:

       

    动画演示:http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/erchashujianli.htm

    4)事实上,上述构造二叉树的过程是使用了二叉树的先序遍历完成的。在二叉树已经构造完成的基础上,分别完成先序遍历、中序遍历、后序遍历和层次遍历。

    先序遍历:先访问根节点,再访问左节点,后访问右节点。如果左节点上还有左子树,继续访问其左节点,然后再访问右节点。

    中序遍历:左节点、根节点、右节点。

    后序遍历:左节点、右节点、根节点。

    层次遍历:首先访问第0层,当i层所有节点访问完之后,再从左向右访问i+1层的各个节点。

    使用递归的方法完成先序遍历、中序遍历、后序遍历,使用队列的方法完成层次遍历。代码如下: 

      1 import java.util.LinkedList;
      2 import java.util.Queue;
      3 public class traversal {
      4     static int step=0;
      5     public static void main(String[] args){
      6         int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
      7         int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
      8         Node root=new Node();
      9         root=createBinaryTree(root,nodeArray);
     10         System.out.println("tree A:");
     11         System.out.println("先序遍历:");
     12         nlr(root);
     13         System.out.println("
    " + "中序遍历:");
     14         lnr(root);
     15         System.out.println("
    " + "后序遍历:");
     16         lrn(root);
     17         System.out.println("
    " + "层次遍历:");
     18         levelTraversal(root);
     19         Node root2=new Node();
     20         step=0;
     21         root2=createBinaryTree(root2,nodeArray2);
     22         System.out.println("
    "+"tree B:");
     23         System.out.println("先序遍历:");
     24         nlr(root2);
     25         System.out.println("
    " + "中序遍历:");
     26         lnr(root2);
     27         System.out.println("
    " + "后序遍历:");
     28         lrn(root2);
     29         System.out.println("
    " + "层次遍历:");
     30         levelTraversal(root2);
     31     }
     32     public static Node createBinaryTree(Node root,int[] nodeArray ){
     33         int val=-1;
     34         try {
     35             val = nodeArray[step];
     36             step++;
     37         }
     38         catch (ArrayIndexOutOfBoundsException ex){
     39             System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
     40         }
     41         if(val<0){
     42             //System.out.println("leaf node");
     43             root=null;
     44             return root;
     45         }
     46         root=new Node(val);///指向新对象
     47         //step++;
     48         root.leftNode=createBinaryTree(root.leftNode,nodeArray);
     49         root.rightNode=createBinaryTree(root.rightNode,nodeArray);
     50         return root;
     51     }
     52     public static void nlr(Node head){
     53         if(head==null){
     54             return;
     55         }
     56         System.out.print(head.value+"	");
     57         nlr(head.leftNode);
     58         nlr(head.rightNode);
     59     }
     60     public static void lnr(Node head){
     61         if(head==null){
     62             return;
     63         }
     64         lnr(head.leftNode);
     65         System.out.print(head.value + "	");
     66         lnr(head.rightNode);
     67     }
     68     public static void lrn(Node head){
     69         if(head==null){
     70             return;
     71         }
     72         lrn(head.leftNode);
     73         lrn(head.rightNode);
     74         System.out.print(head.value + "	");
     75     }
     76     public static void levelTraversal(Node head){
     77         Queue<Node> nodeQueue=new LinkedList<>();
     78         nodeQueue.offer(head);
     79         while(!nodeQueue.isEmpty()){
     80             Node node=nodeQueue.poll();
     81             System.out.print(node.value+"	");
     82             if (node.leftNode!=null){
     83                 nodeQueue.offer(node.leftNode);
     84             }
     85             if(node.rightNode!=null){
     86                 nodeQueue.offer(node.rightNode);
     87             }
     88         }
     89         return;
     90     }
     91 }
     92 class Node{
     93     public int value=-1;
     94     public Node leftNode;
     95     public Node rightNode;
     96     public Node(int val){
     97         value=val;
     98     }
     99     public Node(){
    100     }
    101 }
    View Code

     运行结果图:

     三种遍历的非递归实现: 

     1 //非递归形式的先序遍历
     2     public static void nlr2(Node head){
     3         if (head!=null){
     4             return;
     5         }
     6         Stack<Node> stack=new Stack<>();
     7         stack.push(head);
     8         while (!stack.empty()){
     9             Node temp=stack.peek();
    10             System.out.println(temp.value+"	");
    11             stack.pop();
    12             if(temp.rightNode!=null){
    13                 stack.push(temp.rightNode);
    14             }
    15             if(temp.leftNode!=null){
    16                 stack.push(temp.leftNode);
    17             }
    18         }
    19 
    20     }
    21 
    22 void lnr2(Node *root)//非递归中序遍历
    23 {
    24     stack<Node *> stk;
    25     Node *p = root;
    26     while (p != NULL || !stk.empty())
    27     {
    28         if (p != NULL)
    29             stk.push(p), p = p->left;
    30         else
    31         {
    32             p = stk.top(); stk.pop();
    33             printf("%d ", p->val);
    34             p = p->right;
    35         }
    36     }
    37 }
    38  //非递归形式的后序遍历
    39  public static void lrn2(Node head){
    40         if(head==null){
    41             return;
    42         }
    43         Stack<Node> stack1=new Stack<>();
    44         Stack<Node> stack2=new Stack<>();
    45         stack1.push(head);
    46         while (!stack1.empty()){
    47             Node tmp=stack1.peek();
    48             stack1.pop();
    49             stack2.push(tmp);
    50             if(tmp.leftNode!=null){
    51                 stack1.push(tmp.leftNode);
    52             }
    53             if(tmp.rightNode!=null){
    54                 stack1.push(tmp.rightNode);
    55             }
    56         }
    57        while (!stack2.empty()){
    58            System.out.print(stack2.pop().value + "	");
    59        }
    60     }
    View Code

     参考http://noalgo.info/832.html

     更多代码:

    import java.util.*;
    
    /**
     * Created by hfz on 2016/7/5.
     */
    public class traversal {
        static int step=0;
        public static void main(String[] args){
            int[] nodeArray=new int[]{1,2,4,-1,-1,5,-1,-1,3,-1,6,-1,-1};
            int[] nodeArray2=new int[]{1,2,4,-1,-1,5,9,-1,-1,-1,3,6,7,-1,8,-1,-1,-1,-1};
            Node root=new Node();
            root=createBinaryTree(root,nodeArray);
            System.out.println("tree A:");
            System.out.println("先序遍历:");
            nlr(root);
    
            System.out.println("
    " + "非递归先序遍历:");
            unRecurNLR(root);
            nlr2(root);
    
    
            System.out.println("
    " + "中序遍历:");
            lnr(root);
    
            System.out.println("
    " + "非递归中序遍历:");
            unRecurLNR2(root);
    
    
    
            System.out.println("
    " + "后序遍历:");
            lrn(root);
            System.out.println("
    " + "层次遍历:");
            levelTraversal(root);
            System.out.printf("%n二叉树叶子节点数量%n%d", getLeafNodeNum(root));
    
    
    
            System.out.println("
    " + "二叉树节点总个数:");
            System.out.print(calNodeAmounts(root));
            System.out.println("
    " + "二叉树深度:");
            int i=0;
            System.out.print(calDepth(root, i));
            int k=2;
            System.out.printf("%n第1层到第%d层节点总个数%n",k);
            System.out.print(calKLevalNodeAmounts(root, k, 1));
            System.out.print(String.format("%n第%d层节点个数为%n%d", k, calKthLevel(root, k)));
    
    
    
    
    
            Node root2=new Node();
            step=0;
            root2=createBinaryTree(root2,nodeArray2);
            System.out.println("
    "+"tree B:");
            System.out.println("先序遍历:");
            nlr(root2);
            System.out.println("
    " + "非递归先序遍历:");
            unRecurNLR(root2);
            System.out.println("
    " + "中序遍历:");
            lnr(root2);
    
            System.out.println("
    " + "非递归中序遍历:");
            unRecurLNR2(root2);
    
    
            System.out.println("
    " + "后序遍历:");
            lrn(root2);
            System.out.println("
    " + "层次遍历:");
            levelTraversal(root2);
            System.out.printf("%n二叉树叶子节点数量%n%d", getLeafNodeNum(root2));
    
            System.out.println("
    " + "二叉树节点个数:");
            System.out.print(calNodeAmounts(root2));
            System.out.println("
    " + "二叉树深度:");
            System.out.print(calDepth(root2, i));
            k=4;
            System.out.print(String.format("%n第1层到第%d层节点总个数为:%n%d", k, calKLevalNodeAmounts(root2, k, 1)));
            System.out.print(String.format("%n第%d层节点个数为:%n%d", k, calKthLevel(root2, k)));
    
            System.out.printf("%ntree A和tree B 结构是否相同:%n%b",structureCmp(root,root2));
    
        }
        // 创建二叉树
        public static Node createBinaryTree(Node root,int[] nodeArray ){
            int val=-1;
            try {
                val = nodeArray[step];
                step++;
            }
            catch (ArrayIndexOutOfBoundsException ex){
                System.out.println("(ArrayIndexOutOfBounds,check the nodeArray");
            }
            if(val<0){
                //System.out.println("leaf node");
                root=null;
                return root;
            }
            root=new Node(val);///指向新对象
            //step++;
            root.leftNode=createBinaryTree(root.leftNode,nodeArray);
            root.rightNode=createBinaryTree(root.rightNode,nodeArray);
            return root;
        }
        //先序遍历
        public static void nlr(Node head){
            if(head==null){
                return;
            }
            System.out.print(head.value+"	");
            nlr(head.leftNode);
            nlr(head.rightNode);
        }
        //非递归形式的先序遍历
        /*
        1)申请一个栈来存放节点,首先存入根节点
        2)弹出栈顶节点并打印其值,记为cur,将栈顶节点(cur)的右节点(如果有的话)入栈,将栈顶节点(cur)的左节点入栈
        3)重复2,直至栈为空
         */
        public static void unRecurNLR(Node root){
            Stack<Node> stack=new Stack<>();
            Node cur=root;
            Node rightNode=null;
            Node leftNode=null;
            if(cur==null){
                return;
            }
            stack.push(cur);
            while(!stack.empty()){
                cur=stack.pop();
                System.out.print(cur.value + "	");
                rightNode=cur.rightNode;
                leftNode=cur.leftNode;
                if(rightNode!=null){
                    stack.push(rightNode);
                }
                if(leftNode!=null){
                    stack.push(leftNode);
                }
            }
        }
    
        public static void nlr2(Node head){
            Stack<Node> stack=new Stack<>();
            ArrayList<Integer> list=new ArrayList<>();
            stack.push(head);
            while (!stack.empty()){
                Node temp=stack.peek();
                list.add(temp.value);
                stack.pop();
                if(temp.rightNode!=null){
                    stack.push(temp.rightNode);
                }
                if(temp.leftNode!=null){
                    stack.push(temp.leftNode);
                }
            }
            Integer[] rr=list.toArray(new Integer[]{} );
            System.out.println(Arrays.toString(rr));
        }
    
    
    
    
    
    
    
    
    
    
        //中序遍历
        public static void lnr(Node head){
            if(head==null){
                return;
            }
            lnr(head.leftNode);
            System.out.print(head.value + "	");
            lnr(head.rightNode);
        }
    
        //非递归形式的中序遍历(自己编写)
        /*
        1)申请栈存放节点,令cur=head
        2)将cur指向的节点入栈
        3)令cur=cur.leftNode,如果cur!=null,转2,如果栈为空,算法结束,否则弹出cur指向的节点(栈顶节点)node,并打印node
        4)弹出栈顶节点后,令cur=node.right,转2
         */
    
        public static void unRecurLNR(Node head){
            Node cur=head;
            //Node leftNode=null;
            //Node rightNode=null;
            Stack<Node> stack=new Stack<>();
            stack.push(cur);
            while (!stack.empty()){
                while (cur!=null) {
                    cur=cur.leftNode;
                    if(cur!=null)
                    stack.push(cur);
                }
                cur=stack.pop();
                System.out.print(cur.value+"	");
                cur=cur.rightNode;
                if(cur!=null)
                    stack.push(cur);
    
            }
    
        }
        //非递归形式的中序遍历(书上编写),形式更加简洁。
    
        public static void unRecurLNR2(Node head){
            if(head!=null){
                Node cur=head;
                Stack<Node> stack=new Stack<>();
                //stack.push(cur);
                while (!stack.empty()||cur!=null){
                    if(cur!=null){
                        stack.push(cur);
                        cur=cur.leftNode;
                    }
                    else{
                        cur=stack.pop();
                        System.out.print(cur.value+"	");
                        cur=cur.rightNode;
                    }
                }
    
            }
        }
    
    
    
    
    
    
    
        //后序遍历
        public static void lrn(Node head){
            if(head==null){
                return;
            }
            lrn(head.leftNode);
            lrn(head.rightNode);
            System.out.print(head.value + "	");
        }
        //层次遍历
        public static void levelTraversal(Node head){
            Queue<Node> nodeQueue=new LinkedList<>();
            nodeQueue.offer(head);
            while(!nodeQueue.isEmpty()){
                Node node=nodeQueue.poll();
                System.out.print(node.value+"	");
                if (node.leftNode!=null){
                    nodeQueue.offer(node.leftNode);
                }
                if(node.rightNode!=null){
                    nodeQueue.offer(node.rightNode);
                }
            }
            return;
        }
        //计算二叉树节点总个数
        public static int calNodeAmounts(Node head){
            if(head==null){
                return 0;
            }
            return calNodeAmounts(head.leftNode)+calNodeAmounts(head.rightNode)+1;
        }
        //计算二叉树深度(自己编写)
        public static int calDepth(Node head,int counter){
            if(head==null){
                return counter;
            }
            else {
                counter++;
            }
            int a=calDepth(head.leftNode,counter);
            int b=calDepth(head.rightNode,counter);
            return a>b?a:b;
        }
        //计算二叉树深度(更好实现)
        public static int calDept2(Node head){
            if(head==null){
                return 0;
            }
            int leftDepth=calDept2(head.leftNode);
            int rightDepth=calDept2(head.rightNode);
            return leftDepth>rightDepth?leftDepth+1:rightDepth+1;
        }
    
        //第1层到第k层节点总数量(自己编写)
    
        public static int calKLevalNodeAmounts(Node head,int KLevel,int currentLevel){
    
            if(head==null){
                return 0;
            }
            if(currentLevel<= KLevel){
                return calKLevalNodeAmounts(head.leftNode,KLevel,currentLevel+1)+calKLevalNodeAmounts(head.rightNode,
                        KLevel,currentLevel+1)+1;
            }
            return 0;
        }
        //第k层节点数量
        public static int calKthLevel(Node head,int k){
            if(head==null||k<1){
                return 0;
            }
            if(k==1){
                return 1;
            }
            int leftAmounts=calKthLevel(head.leftNode,k-1);
            int rightAmounts=calKthLevel(head.rightNode,k-1);
            return leftAmounts+rightAmounts;
        }
        //计算叶子节点个数
        public static int getLeafNodeNum(Node head){
            if(head==null){
                return 0;
            }
            if(head.leftNode==null&&head.rightNode==null){
                return 1;
            }
            int leftNum=getLeafNodeNum(head.leftNode);
            int rightNum=getLeafNodeNum(head.rightNode);
            return leftNum+rightNum;
        }
    
        //判断两个二叉树结构是否相同
        public static boolean structureCmp(Node head1,Node head2){
            if(head1==null&&head2==null){
                return true;
            }
            else if(head1==null||head2==null){
                return false;
            }
            boolean leftResult=structureCmp(head1.leftNode,head2.leftNode);
            boolean rightResult=structureCmp(head1.rightNode,head2.rightNode);
            return leftResult&&rightResult;
        }
    
        //求二叉树的镜像
        public static Node Mirror(Node head){
            if(head==null){
                return null;
            }
    
            Node leftNode=Mirror(head.leftNode);
            Node rightNode=Mirror(head.rightNode);
            head.leftNode=rightNode;
            head.rightNode=leftNode;
            return head;
        }
    
    }
    class Node{
        public int value=-1;
        public Node leftNode;
        public Node rightNode;
        public Node(int val){
            value=val;
        }
        public Node(){
        }
    }
    View Code
  • 相关阅读:
    Socket网络编程--简单Web服务器(4)
    GCC学习笔记
    字符分隔符'1'(u0001)的困惑
    g++编译时遇到问题undefined reference to
    ROS学习笔记(三)
    cJSON笔记
    ROS学习笔记(二)
    ROS学习笔记(一)
    ffmpeg推流方式采用TCP协议
    Android OS的image文件组成
  • 原文地址:https://www.cnblogs.com/lz3018/p/5644364.html
Copyright © 2020-2023  润新知