【数据结构】二叉树

 

特点

 

1、二叉树的每个结点至多只有二棵子树(不存在度大于2的结点);

2、在非空二叉树的k层上,至多有2^(k-1)个节点(k>0);

3、高度为k的二叉树中,最多有2^k-1个节点(k>0);

4、对于任何一棵非空的二叉树,如果叶节点个数为n0,度数为2的节点个数为n2,则有: n0 = n2 + 1。

注:通过网上学习得知,国外的教材对于数的高度和深度通常都是从0开始,而国内比较偏向从1开始,所以要注意这个概念上的定义,例如我上文定义的(K>1)。

(从二叉树特点判断,以上二图中的树都为二叉树)

 

满二叉树

 

满二叉树是二叉树的一种,除了具备二叉树的特征,还需要满足的条件是:若一棵深度为k,且有2^k-1个节点称之为满二叉树。就是一个挂满节点的二叉树,叫满二叉树,如下图:

以上二叉树为满二叉树,其中深度K=3,总节点数为2^3-1 = 7。

 

完全二叉树

 

除基本二叉树特点外,还需要满足的条件是除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点。换句话说,叶子结点只可能在最大的两层上出现,对任意结点,若其右分支下的子孙最大层次为L,则其左分支下的子孙的最大层次必为L 或 L+1;

(从完全二叉树特点判断,以上二图中的树都为完全二叉树)

 

由于二叉树的特点可以得出:

 

1、满二叉树是一颗挂满节点的数,所以满二叉树一定是完全二叉树,而完全二叉树不一定是满二叉树。

 

2、根据公式进行推导,假设n0是度为0的结点总数(即叶子结点数),n1是度为1的结点总数,n2是度为2的结点总数,由二叉树的性质可知:n0=n2+1,则n= n0+n1+n2(其中n为完全二叉树的结点总数),由上述公式把n2消去得:n= 2n0+n1-1,由于完全二叉树中度为1的结点数只有0或1两种可能,由此得到n0=(n+1)/2或n0=n/2。总结起来,就是 n0=[n/2],其中[]表示上取整。如上图左边的完全二叉树,n = 6;得知n0 = [6/2] = 3;右边的同理,n0 = [5/2] = 3。

 

二叉树的实现练习

对树的基本运算操作有获取树的高度、获取树的节点数、获取节点的双亲节点和对树遍历,其中,遍历二叉树 是指以一定的次序访问二叉树中的每个结点,遍历二叉树的过程实质是把二叉树的结点进行线性排列的过程,那么遍历的结果得到一个线性序列。从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:

(1)访问结点本身(N),

(2)遍历该结点的左子树(L),

(3)遍历该结点的右子树(R)。

以上三种操作有六种执行次序:NLR、LNR、LRN、NRL、RNL、RLN。因为前三种次序与后三种次序对称,故只需要讨论先左后右的前三种次序并加以解析。NLR、LNR和LRN分别又称为先根遍历(前序遍历DLR)、中根遍历(中序遍历LDR)和后根遍历(后续遍历LRD)。

 

前序遍历:ABDECF

前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。

 

中序遍历:DBEAFC

中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。

 

后序遍历:DEBFCA

后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。

 

Java实现例子

  1 public class BinaryTree {
  2     
  3     private TreeNode root=null;
  4     
  5     /** 
  6      * 创建一棵二叉树 
  7      *           A 
  8      *     B          C 
  9      *  D     E            F 
 10      */  
 11     public void createBinTree(){
 12         TreeNode root_A = new TreeNode("A");
 13         TreeNode node_B = new TreeNode("B");
 14         TreeNode node_C = new TreeNode("C");
 15         TreeNode node_D = new TreeNode("D");
 16         TreeNode node_E = new TreeNode("E");
 17         TreeNode node_F = new TreeNode("F");
 18         root = root_A;
 19         root.leftChild=node_B;  
 20         root.rightChild=node_C;  
 21         root.leftChild.leftChild=node_D;  
 22         root.leftChild.rightChild=node_E;  
 23         root.rightChild.rightChild=node_F;  
 24     }
 25     
 26     /**
 27      * 获取树的高度
 28      * @param subTree 
 29      * @return
 30      */
 31     private int height(TreeNode subTree){  
 32         if(subTree==null)  
 33             return 0;//递归结束:空树高度为0  
 34         else{  
 35             int i=height(subTree.leftChild);  
 36             int j=height(subTree.rightChild);  
 37             return (i<j)?(j+1):(i+1);  
 38         }  
 39     }
 40     
 41     /**
 42      * 获取数的节点数
 43      * @param subTree
 44      * @return
 45      */
 46     private int size(TreeNode subTree){  
 47         if(subTree==null){  
 48             return 0;  
 49         }else{  
 50             return 1+size(subTree.leftChild)+size(subTree.rightChild);
 51         }  
 52     }  
 53     
 54     /**
 55      * 获取节点的双亲节点
 56      * @param element
 57      * @return
 58      */
 59     public TreeNode parent(TreeNode element){  
 60         return (root==null|| root==element)?null:parent(root, element);
 61     } 
 62     
 63     public TreeNode parent(TreeNode subTree,TreeNode element){
 64         if(subTree==null)
 65             return null;  
 66         if(subTree.leftChild==element||subTree.rightChild==element)  
 67             //返回父结点地址  
 68             return subTree;  
 69         TreeNode p;  
 70         //现在左子树中找,如果左子树中没有找到,才到右子树去找  
 71         if((p=parent(subTree.leftChild, element))!=null)  
 72             //递归在左子树中搜索  
 73             return p;  
 74         else  
 75             //递归在右子树中搜索  
 76             return parent(subTree.rightChild, element);  
 77     }
 78     
 79     //前序遍历  
 80     public void preOrder(TreeNode subTree){  
 81         if(subTree!=null){
 82             visted(subTree);  
 83             preOrder(subTree.leftChild); 
 84             preOrder(subTree.rightChild); 
 85         }
 86     }  
 87       
 88     //中序遍历  
 89     public void inOrder(TreeNode subTree){  
 90         if(subTree!=null){  
 91             inOrder(subTree.leftChild);  
 92             visted(subTree);  
 93             inOrder(subTree.rightChild);  
 94         }  
 95     }  
 96       
 97     //后续遍历  
 98     public void postOrder(TreeNode subTree) {  
 99         if (subTree != null) {  
100             postOrder(subTree.leftChild);  
101             postOrder(subTree.rightChild);  
102             visted(subTree);  
103         }  
104     }  
105     
106     public void visted(TreeNode subTree){  
107         System.out.print(subTree.data);
108     }
109     
110     /** 
111      * 二叉树的节点数据结构 
112      */  
113     private class  TreeNode{
114         
115         private String data=null;
116         private TreeNode leftChild=null;
117         private TreeNode rightChild=null;
118           
119         public TreeNode(){}
120 
121         public TreeNode(String data){  
122             this.data=data; 
123         }  
124     } 
125     
126     public static void main(String[] args) {
127         BinaryTree bt = new BinaryTree();
128         bt.createBinTree();
129         System.out.println("tree height:"+bt.height(bt.root));
130         bt.preOrder(bt.root);
131         System.out.println("---前序遍历");
132         bt.inOrder(bt.root);
133         System.out.println("---中序遍历");
134         bt.postOrder(bt.root);
135         System.out.println("---后序遍历");
136     }
137 }

执行结果:

tree height:3
ABDECF---前序遍历
DBEAFC---中序遍历
DEBFCA---后序遍历

posted @ 2016-05-03 11:34  wc的一些事一些情  阅读(364)  评论(0编辑  收藏  举报