算法:二叉树理论知识

来源:互联网 发布:windows nt 6.1.7601 编辑:程序博客网 时间:2024/06/07 22:53

一、树结构的基础术语

树的示例
  树的结点:包含一个数据元素及若干指向其子树的分支。
  结点的度(Degree):结点拥有的子树数。eg:上图中,A的度为3,C的度为1,F的度为0。
  叶子结点(Leaf)或终端结点:度为0的结点。eg:上图中,K,L,F,G,H,I,J都是树的叶子结点。
  分支结点或非终端结点:度不为0的结点。
  树的度:树内各结点的度的最大值。eg:上图中,树的度为3。
  结点的孩子(Child):结点的子树的根称为该结点的孩子。相应的该节点称为孩子的双亲(Parent)。
  eg:上图中,D为A的子树的根,则D是A的孩子,而A是D的双亲。
  兄弟结点(Sibling):同一个双亲的孩子之间互称为兄弟。
  eg:结点B,C,D都有同一个双亲A,所以B,C,D互称为兄弟结点。
  结点的祖先:从根到该结点所经分支上的所有结点。eg:M的祖先为A,D,H。
  子孙结点:以某结点为根的子树中的任一结点都称为该结点的子孙。eg:B的子孙为E,K,L 和 F。
  结点的层次(Level):从根开始定义,根为第一层,根的孩子为第二层。
  eg:上图中,树总共有4层:A为第一层;B,C,D为第二层,依次递推。
  树的深度(Depth)或高度:树中结点的最大层次。eg:上图中,树的深度为4。
  有序树:如果将树中的各子树看成从左至右是有次序的(即不能互换),则称该树为有序树;
  否则为无序树。
  

二、二叉树定义

  二叉树(Binary Tree):是一种特殊的树型结构,它的特点:
  1.每个结点至多只有两颗子树(即二叉树中不存在度大于2的结点);
  2.二叉树的子树有左右之分,其次序不能任意颠倒(即二叉树是有序树)。
  满二叉树:深度为k且有2^k-1个结点的二叉树称为满二叉树。
  完全二叉树:对满二叉树的结点进行连续标号,约定编号从根结点起,自上而下,自左至右,由此引出完全二叉树定义。深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称之为完全二叉树。

二叉树性质

   二叉树具有下列重要特性:
   性质1:在二叉树的第i层上至多有2^(i-1)个结点,其中i >= 1。
   性质2:深度为k的二叉树至多有2^k-1个结点,其中k >= 1。
   性质3:对于任意一棵二叉树T,如果其叶子结点个数为n0,度为2的结点个数为n2,则n0=n2+1。
   证明:设n1为二叉树度为1的结点个数。因为二叉树中所有结点的度均小于或等于2。所以其结点总数n为:
      n=n0 + n1 +n2  (6-1)
    再看二叉树中的分支数。除了根节点外,其余结点都有一个分支进入,设B是分支总数,则n=B+1。由于这些分支是由度为1或2的结点射出的,所以又有B=n1+n2。于是得:
      n=n1 + 2 * n2 + 1  (6-2)    
   由式 (6-1)和(6-2)得:
     n0 = n2 + 1
   性质4:具有n个结点的完全二叉树深度为log2n(向下取整) +1。   
  

二叉树构建(java实现)

代码中int[] levelorder2是二叉树层次遍历得到的数组,0代表结点为null。

int[] levelorder2 = {0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0}; //特别注意:数组index=0的位置不使用TreeNode root2 = TreeNodeUtil.makeBinaryTreeByArray(levelorder2, 1);
    public static TreeNode makeBinaryTreeByArray(int[] a, int index){        if(index < a.length){            int value = a[index];            if(value != 0){                TreeNode node = new TreeNode(value);                //a[index]=0;                node.left = makeBinaryTreeByArray(a, index*2);                node.right = makeBinaryTreeByArray(a, index*2+1);                   return node;            }        }        return null;    }

二叉树遍历(java实现)

  先序遍历(深度优先遍历DFS)、中序遍历、后序遍历,广度优先遍历BFS
  1.先序遍历

   /**     * 先序遍历二叉树:递归实现     * @param root     */    public static void preTraverse(TreeNode root){        if(root != null){            System.out.print(root.val + " ");            preTraverse(root.left);            preTraverse(root.right);        }    }

  1.1先序遍历—非递归实现(使用栈数据结构)

    /**     * 先序遍历:非递归实现(DFS深度优先遍历)     *      * @param root     */    public static void perTraverseNoRecursion(TreeNode root){        Stack<TreeNode> stack = new Stack<TreeNode>();        stack.push(root);        while(!stack.isEmpty()){            TreeNode node = stack.pop();            System.out.print(node.val + " ");            if (node.right != null) {//先右后左,右节点先入栈                stack.push(node.right);            }            if (node.left != null) {                stack.push(node.left);            }        }//end while    }//end method

  2.中序遍历

   /**     * 中序遍历二叉树:递归实现     * @param root     */    public static void inTraverse(TreeNode root){        if(root != null){            inTraverse(root.left);            System.out.print(root.val + " ");            inTraverse(root.right);        }    }

  3.后序遍历

   /**     * 后序遍历二叉树:递归实现     * @param root     */    public static void postTraverse(TreeNode root){        if(root != null){            postTraverse(root.left);            postTraverse(root.right);            System.out.print(root.val + " ");        }    }

  4.BFS遍历  

   /**     * 广度优先遍历BFS:非递归实现     * @param root     *      * 说明:队列是先入先出的数据结构(FIFO)  very nice!     */    public static void levelTraverse(TreeNode root) {        Queue<TreeNode> queue = new LinkedList<TreeNode>();        queue.offer(root);// 从根节点入队列        while (!queue.isEmpty()) {// 在队列为空前反复迭代            TreeNode TreeNode = queue.poll();// 取出队列首节点            System.out.print(TreeNode.val + " ");            if (TreeNode.left != null)                queue.offer(TreeNode.left);// 左孩子入列            if (TreeNode.right != null)                queue.offer(TreeNode.right);// 右孩子入列        }    }

三、二叉搜索树

1. 二叉搜索树定义

  二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
1.若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2.若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3.任意节点的左、右子树也分别为二叉查找树;
4.没有键值相等的节点。
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构 

2. 平衡二叉搜索树

  平衡二叉搜索树(Balanced Binary Tree)是一种结构平衡的二叉搜索树,即叶节点深度差不超过1,它能在O(log n)内完成插入、查找和删除操作。

3. 使用排序数组,构建平衡二叉搜索树

    /**     * 通过一个升序数组,构建平衡二叉搜索树(Binary Search Tree)     *     * @param nums     * @return     */    public static TreeNode sortedArrayToBST(int[] num) {        if (num == null || num.length == 0) {            return null;        }        return helper(num, 0, num.length - 1);    }    public static TreeNode helper(int[] num, int low, int high) {        if (low > high) { // Done 递归出口            return null;        }        int mid = (low + high) / 2;        TreeNode node = new TreeNode(num[mid]);        node.left = helper(num, low, mid - 1);  //左半部分递归        node.right = helper(num, mid + 1, high); //右半部分递归        return node;    }

4. 平衡二叉搜索树,插入结点

/**     * 二叉搜索树(Binary Search Tree):插入元素     * @param root     * @param element     * @return     */    public static boolean insertBST(TreeNode root, int element){        if(root == null){  //空树情况            root = new TreeNode();            root.val = element;            root.left = root.right = null;        }else if(element == root.val){ //值相等情况            return false;        }else if(element < root.val){            insertBST(root.left, element);        }else{            insertBST(root.right, element);        }        return true;    }//end method