本文共 5884 字,大约阅读时间需要 19 分钟。
二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者是由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树中的每个节点都定义了一颗左子树和一颗右子树。每棵子树自身就是一棵树。
二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树。具有n个节点的完全二叉树的深度为log2n+1。深度为k的完全二叉树,至少有2^(k-1)个节点,至多有2^k-1个节点。
二叉树在图论中是这样定义的:二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量,这样的结构叫做森林。
二叉树是递归定义的,其结点有左右子树之分,逻辑上二叉树有五种基本形态:
(1)空二叉树
(2)只有一个根结点的二叉树 (3)只有左子树 (4)只有右子树 (5)完全二叉树注意:尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形。[1]
完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
树的结点:包含一个数据元素及若干指向子树的分支;
孩子结点:结点的子树的根称为该结点的孩子;
双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;
兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点;
祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙
结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
树的深度:树中最大的结点层
结点的度:结点子树的个数
树的度: 树中最大的结点度。
叶子结点:也叫终端结点,是度为 0 的结点;
分枝结点:度不为0的结点;
有序树:子树有序的树,如:家族树;
无序树:不考虑子树的顺序;
(1) 在非空二叉树中,第i层的结点总数不超过 , i>=1;
(2) 深度为h的二叉树最多有 个结点(h>=1),最少有h个结点;
(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
(4) 具有n个结点的完全二叉树的深度为
(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。
(6)给定N个节点,能构成h(N)种不同的二叉树。
h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
package com.bean.binarytreedemo;public class TreeNode { int data; //节点值 TreeNode leftChild; //左子树 TreeNode rightChild; //右子树 TreeNode(){ this.leftChild=null; this.rightChild=null; this.data=-1; } TreeNode(int data){ this.leftChild=null; this.rightChild=null; this.data=data; } public TreeNode(int data, TreeNode leftChild, TreeNode rightChild) { this.data = data; this.leftChild = leftChild; this.rightChild = rightChild; } public int getData() { return data; } public void setData(int data) { this.data = data; } public TreeNode getLeftChild() { return leftChild; } public void setLeft(TreeNode leftChild) { this.leftChild = leftChild; } public TreeNode getRightChild() { return rightChild; } public void setRight(TreeNode rightChild) { this.rightChild = rightChild; }}
给定下面的数组,代表二叉树节点的值,建立一颗二叉树。
private int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; private static ListnodeList = null;
算法设计:
public void createBinTree() { nodeList = new LinkedList(); // 将一个数组的值依次转换为Node节点 for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) { nodeList.add(new TreeNode(array[nodeIndex])); } // 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树 for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) { // 左孩子 nodeList.get(parentIndex).leftChild = nodeList .get(parentIndex * 2 + 1); // 右孩子 nodeList.get(parentIndex).rightChild = nodeList .get(parentIndex * 2 + 2); } // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理 int lastParentIndex = array.length / 2 - 1; // 左孩子 nodeList.get(lastParentIndex).leftChild = nodeList .get(lastParentIndex * 2 + 1); // 右孩子,如果数组的长度为奇数才建立右孩子 if (array.length % 2 == 1) { nodeList.get(lastParentIndex).rightChild = nodeList .get(lastParentIndex * 2 + 2); } }
/* * 二叉树的层次遍历 * */ public static ArrayList> levelOrder(TreeNode root){ ArrayList > result = new ArrayList >(); if(root == null){ return result; } Queue queue = new LinkedList (); queue.offer(root); while(!queue.isEmpty()){ int size = queue.size(); ArrayList level = new ArrayList (); for(int i = 0;i < size ;i++){ TreeNode node = queue.poll(); level.add(node.data); if(node.leftChild != null){ queue.offer(node.leftChild); } if(node.rightChild != null){ queue.offer(node.rightChild); } } result.add(level); } System.out.println(result); return result; }
遍历结果为:
二叉树的层次遍历为: [[1], [2, 3], [4, 5, 6, 7], [8, 9]]/* * 判断二叉树是否为一颗完全二叉树 * */ public static boolean isCompleteTreeNode(TreeNode root){ if(root == null){ return false; } Queuequeue = new LinkedList (); queue.add(root); boolean result = true; boolean hasNoChild = false; while(!queue.isEmpty()){ TreeNode current = queue.remove(); if(hasNoChild){ if(current.leftChild!=null||current.rightChild!=null){ result = false; break; } }else{ if(current.leftChild!=null&¤t.rightChild!=null){ queue.add(current.leftChild); queue.add(current.rightChild); }else if(current.leftChild!=null&¤t.rightChild==null){ queue.add(current.leftChild); hasNoChild = true; }else if(current.leftChild==null&¤t.rightChild!=null){ result = false; break; }else{ hasNoChild = true; } } } return result; }
该二叉树的形态实际如下图所示: