树结构

  1. 树的基本概念

    除了根节点之外每个结点只有一个父节点,根节点没有父节点;除了叶子节点,所有节点都有一个或多个子节点,叶子节点没有子节点。

    二叉树
    在二叉树中每个节点最多只有两个子节点

    二叉树的性质
    a. 在非空二叉树的k层上,至多有2^(k-1)个节点(k>=1)
    b. 高度为k的二叉树中,最多有2^k-1个节点(k>=1)
    c. 对于任何一棵非空的二叉树,如果叶节点个数为n0,度数为2的节点个数为n2,则有: n0 = n2 + 1

    完全二叉树性质:

    除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点

    a. 具有n个节点的完全二叉树的高度k为[log2n]
    b. 对于具有n个节点的完全二叉树,如果按照从上(根节点)到下(叶节点)和从左到右的顺序 对二叉树中的所有节点从0开始到n-1进行编号,则对于任意的下标为k的节点,有:

    如果k=0,则它是根节点,它没有父节点;如果k>0,则它的父节点的下标为[(i-1)/2];
    如果2k+1 <= n-1,则下标为k的节点的左子结点的下标为2k+1;否则,下标为k的节点没有左子结点.
    如果2k+2 <= n-1,则下标为k的节点的右子节点的下标为2k+2;否则,下标为k的节点没有右子节点

满二叉树

除最后一层无任何子节点外,每一层上的所有结点都有两个子结点或0个子节点的二叉树。
在满二叉树中,叶节点的个数比分支节点的个数多1

  1. 二叉树的遍历

(1)前序遍历
a:非递归

/**
     * 二叉树的前序遍历  非递归方式
     * 算法思想:
     * (1)若当前节点不为空,则输出当前节点,并把该节点压入栈,如果当前节点左子树不为空,指向左子树,
     *    
     * (2)若当前节点为空,但栈不为空,读取并删除栈顶元素,指向栈顶元素的右节点,依次循环
     * @param root
     */
    public static void preOrder_notrec(TreeNode root){
        //定义栈,用来存放节点
        Stack<TreeNode> s=new Stack<TreeNode>();

        while(root!=null || !s.empty()){
            if(root!=null ){
                System.out.println(root.val);
                s.push(root);
                root=root.left;
            }else{
                root=(TreeNode) s.pop();
                root=root.right;
                }
            }
    }
b:递归
/**
     * 二叉树的前序遍历 递归方式
     * @param root
     */
    public static void preOrder_rec(TreeNode root){
        if(root!=null){
            System.out.println(root.val);
            if (root.left!=null)
                preOrder_rec(root.left);
            if(root.right!=null)
                preOrder_rec(root.right);
        }
    }

(2)中序遍历
a:非递归

/**
     * 二叉树的中序遍历的非递归实现方式
     * 算法思路:
     * 
     * @param root
     */
    public static void midOrder_notrec(TreeNode root){
        //定义栈,用来存放节点
        Stack<TreeNode> s=new Stack<TreeNode>();

        while(root!=null || !s.empty()){
            if(root!=null ){
                s.push(root);
                root=root.left;
            }else{
                root=(TreeNode) s.pop();
                System.out.println(root.val);
                root=root.right;
                }
            }
    }

b:递归


    /**
     * 二叉树的中序遍历 递归方式
     * @param root
     */
    public static void midOrder_rec(TreeNode root){
        if(root!=null){
            if (root.left!=null)
                preOrder_rec(root.left);
            System.out.println(root.val);
            if(root.right!=null)
                preOrder_rec(root.right);
        }
    }

(3) 后序遍历
a:非递归

/**
     * 二叉树的后序遍历的非递归实现方式
     * 算法思路:
     * 
     * @param root
     */
    public static void postOrder_notrec(TreeNode root){

        Stack<TreeNode> s = new Stack<TreeNode>();//定义栈,用来存放节点

        TreeNode p = root;//pre标记最近出栈的节点,用于判断是否是p节点的右孩子,如果是的话,就可以访问p节点

        TreeNode pre = p;//flag标记是出栈还是继续将左孩子进栈

        boolean flag = true;
        while(p!=null || !s.isEmpty()) {
           if(p!=null  && flag) {
            s.push(p);
            p = p.left;
           }else 
           {
            if(s.isEmpty()) return;
            p = (TreeNode)s.peek();
                if(p.right != null && p.right!=pre) {
                    p = p.right;
                    flag = true;
                }else {
                    p = (TreeNode)s.pop();
                    System.out.println(p.val);;
                    flag = false;
                    pre = p;
                }
           }
          }
    }

b:递归

/**
     * 二叉树的后序遍历 递归方式
     * @param root
     */
    public static void postOrder_rec(TreeNode root){
        if(root!=null){
            if (root.left!=null)
                preOrder_rec(root.left);
            if(root.right!=null)
                preOrder_rec(root.right);
            System.out.println(root.val);
        }
    }

3:已知二叉树的前序遍历和中序遍历,求该二叉树结构

/**
     * 已知二叉树的前序遍历和后序遍历,重新构造该二叉树
     * 并返回根节点
     * @param preOrder
     * @param begin 根节点开始的地方:从1开始
     * @param inOrder 
     * @param end   该子树结束的地方:起始节点从1开始
     * @param len  该树的长度
     * @param root  
     * @return
     */
    public static TreeNode ReBuild(String preOrder,int begin,String inOrder, int end,int len){
        if(preOrder==null || preOrder.length()==0 || inOrder==null || inOrder.length()==0
                || len<=0){
            return null;
        }
        //简历根节点
        /*int和char的转换可能跟char是宽度为16位的实体,用utf-8编码有关系*/
        /*方法1:要通过Character的getNumericValue方法把char类型转换为int类型*/
        TreeNode root=new TreeNode(Character.getNumericValue(preOrder.charAt(begin-1)));
        /*方法2:或者先把char转换为String,再讲String转换为int*/
        //int temp=Integer.parseInt((String.valueOf(preOrder.charAt(begin-1))));

        //递归终结条件:子树只有一个节点
        if(len==1){
            return root;
        }

        //分拆子树的左子树和右子树  
        int i=0;
        while(i<len){
            if(preOrder.charAt(begin-1)==inOrder.charAt(end-i))
                break;
            i++;
        }

        //建立子树的左子树  
        root.left=ReBuild(preOrder,begin+1,inOrder,end-i-1,len-1-i);
        //建立子树的右子树  
        root.right=ReBuild(preOrder,begin+len-i,inOrder,end,i);
        return root;

    }
/**
     * 已知二叉树的前序遍历和中序遍历,确定二叉树
     * @param preOrder
     * @param start  开始的节点位置:起始节点从0开始
     * @param inOrder  
     * @param end  结束的位置,起始节点从0开始
     * @param len  树的节点个数
     * @param root
     * @return
     */
    public static TreeNode buildTree(char[] preOrder, int start,  
            char[] inOrder, int end, int length){
        if (preOrder == null || preOrder.length == 0 || inOrder == null  
                || inOrder.length == 0 || length <= 0) {  
            return null;  
        }  

        //确定根节点
        char value = preOrder[start];  

        TreeNode root = new TreeNode(value);  
        System.out.println(root.val);

        //跳出循环条件:只有一个节点时
        if (length == 1)  
            return root;  

        //确定左右子树
        int i = 0;  
        while (i < length) {  
            if (value == inOrder[end - i]) {  
                break;  
            }  
            i++;  
        }  

        //左子树
        root.left = buildTree(preOrder, start + 1, inOrder, end - i - 1, length - 1 - i);  
        //右子树  
        root.right = buildTree(preOrder, start + length - i, inOrder, end, i );  

        return root;  
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章