Java实现二叉树的定义和递归实现

来源:互联网 发布:数据库scheme例子 编辑:程序博客网 时间:2024/05/29 04:52

定义


最多有两棵子树的有序树,称为二叉树。二叉树是一种特殊的

递归定义:二叉树是n(n>=0)个有限结点构成的集合。N=0称为空二叉树;n>0的二叉树由一个根结点和两互不相交的,分别称为左子树和右子树的二叉树构成。

二叉树中任何结点的第1个子树称为其左子树,左子树的根称为该结点的左孩子;二叉树中任何结点的第2个子树称为其右子树,左子树的根称为该结点的右孩子。如下图是一个二叉树:

图1.二叉树

满二叉树和完全二叉树

在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且叶子结点都在同一层上,这样的二叉树称作满二叉树。一棵深度为k且由2k-1个结点的二叉树称为满二叉树。

如果一棵具有n个结点的二叉树的结构与满二叉树的前n个结点的结构相同,这样的二叉树称作完全二叉树

图2. 满二叉树和完全二叉树


基本性质


这里规定二叉树的根结点的层次为1。

性质1:则二叉树的第i 层最多有2i-1个结点(在此二叉树的层次从1开始,i≥1)

性质2:深度为k的二叉树最多有2k-1个结点。(k≥1)

性质3:对任何一棵二叉树T, 如果其叶结点个数为n0, 度为2的非叶结点个数为n2, 则有

             n0 = n2 + 1

性质4:具有 n(n>0)个结点的完全二叉树的深度为⎣log2n⎦+1;⎦x⎦表示不超过x的最大整数。

性质5:如果对一棵有n个结点的完全二叉树的结点按层序编号(从第1层到第⎣l og2n⎦ +1层,每层从左到右),则对任一结点i(1≤i≤n),有:

(1)如果i=1,则结点i无双亲,是二叉树的根;如果i>1,则其双亲是结点⎣i/2⎦。

(2) 如果2i<=n, 则结点i的左孩子结点是2i;否则,结点i为叶子结点,无左孩子结点。

(3)如果2i+1<=n,则结点i的右孩子是结点2i+1; 否则,结点i为叶子结点,无右孩子结点。


抽象数据类型


数据元素:具有相同特性的数据元素的集合。

结构关系:树中数据元素间的结构关系由二叉树的定义确定。

基本操作:树的主要操作有

(1)创建树IntTree(&T)

(2)销毁树DestroyTree(&T)

(3)构造树CreatTree(&T,deinition)

(4)置空树ClearTree(&T)

(5)判空树TreeEmpty(T)

(6)求树的深度TreeDepth(T)

(7)获得树根Root(T)

(8)获取结点Value(T,cur_e,&e),将树中结点cur_e存入e单元中。

(9)数据赋值Assign(T,cur_e,value),将结点value,赋值于树T的结点cur_e中。

(10)获得双亲Parent(T,cur_e),返回树T中结点cur_e的双亲结点。

(11)获得最左孩子LeftChild(T,cur_e),返回树T中结点cur_e的最左孩子。

(12)获得右兄弟RightSibling(T,cur_e),返回树T中结点cur_e的右兄弟。

(13)插入子树InsertChild(&T,&p,i,c),将树c插入到树T中p指向结点的第i个子树之前。

(14)删除子树DeleteChild(&T,&p,i),删除树T中p指向结点的第i个子树。

(15)遍历树TraverseTree(T,visit())

二叉树的实现


二叉树接口BTree

 

[java] view plaincopy
  1. package datastructure.tree.btree;  
  2.   
  3. public interface BTree {  
  4.     /** 
  5.      * 添加左子树 
  6.      * @param lChild 左子树 
  7.      */  
  8.     public void addLeftTree(BTree lChild);  
  9.     /** 
  10.      * 添加右子树 
  11.      * @param rchild 右子树 
  12.      */  
  13.     public void addRightTree(BTree rchild) ;  
  14.     /** 
  15.      * 置空树 
  16.      */  
  17.     public void clearTree();  
  18.     /** 
  19.      * 求树的深度 
  20.      * @return 树的深度 
  21.      */  
  22.     public int dept();  
  23.     /** 
  24.      * 求左孩子 结点 
  25.      * @return 
  26.      */  
  27.     public BTree getLeftChild();  
  28.       
  29.     /** 
  30.      * 求右孩子结点 
  31.      * @return 
  32.      */  
  33.     public BTree getRightChild();  
  34.     /** 
  35.      * 获得根结点的数据 
  36.      * @return 
  37.      */  
  38.     public Object getRootData();  
  39.     /** 
  40.      * 是否有左子树 
  41.      * @return 
  42.      */  
  43.     public boolean hasLeftTree();  
  44.     /** 
  45.      * 是否有右子树 
  46.      * @return 
  47.      */  
  48.     public boolean hasRightTree();  
  49.     /** 
  50.      * 判断是否为空树 
  51.      * @return 如果为空,返回true,否则返回false 
  52.      */  
  53.     public boolean isEmpty();  
  54.     /** 
  55.      * 判断是否为叶子结点 
  56.      * @return 
  57.      */  
  58.     public boolean isLeaf();  
  59.     /** 
  60.      * 删除左子树 
  61.      */  
  62.     public void removeLeftChild();  
  63.     /** 
  64.      * 删除右子树 
  65.      */  
  66.     public void removeRightChild();  
  67.     /** 
  68.      * 获得树根 
  69.      * @return 树的根 
  70.      */  
  71.     public BTree root();  
  72.     /** 
  73.      * 设置根结点的数据 
  74.      */  
  75.     public void setRootData(Object data);  
  76.     /** 
  77.      * 求结点数 
  78.      * @return 结点的个数  
  79.      */  
  80.     public int size();  
  81. }  

二叉链表的实现

[java] view plaincopy
  1. package datastructure.tree.btree;  
  2.   
  3. public class LinkBTree implements BTree {  
  4.     private Object data;  
  5.     private BTree lChild;  
  6.     private BTree rChild;  
  7.       
  8.     public LinkBTree() {  
  9.         this.clearTree();  
  10.     }  
  11.     public LinkBTree(Object data) {  
  12.         this.data = data;  
  13.         this.lChild = null;  
  14.         this.rChild = null;  
  15.     }  
  16.     @Override  
  17.     public void addLeftTree(BTree lChild) {  
  18.         this.lChild = lChild;  
  19.     }  
  20.   
  21.     @Override  
  22.     public void addRightTree(BTree rChild) {  
  23.         this.rChild = rChild;  
  24.     }  
  25.   
  26.     @Override  
  27.     public void clearTree() {  
  28.         this.data = null;  
  29.         this.lChild = null;  
  30.         this.rChild = null;  
  31.     }  
  32.   
  33.     @Override  
  34.     public int dept() {  
  35.         return dept(this);  
  36.     }  
  37.       
  38.     private int dept(BTree btree) {  
  39.         if(btree.isEmpty()) {  
  40.             return 0;  
  41.         }else if(btree.isLeaf()) {  
  42.             return 1;  
  43.         } else {  
  44.             if(btree.getLeftChild() == null) {  
  45.                 return dept(btree.getRightChild()) + 1;  
  46.             } else if(btree.getRightChild() == null) {  
  47.                 return dept(btree.getLeftChild()) + 1;  
  48.             } else {  
  49.                 return Math.max(dept(btree.getLeftChild()), dept(btree.getRightChild()))+1;  
  50.             }  
  51.         }  
  52.     }  
  53.   
  54.     @Override  
  55.     public BTree getLeftChild() {  
  56.         return lChild;  
  57.     }  
  58.   
  59.   
  60.     @Override  
  61.     public BTree getRightChild() {  
  62.         return rChild;  
  63.     }  
  64.   
  65.     @Override  
  66.     public Object getRootData() {  
  67.         return data;  
  68.     }  
  69.   
  70.     @Override  
  71.     public boolean hasLeftTree() {  
  72.         if(lChild != null)  
  73.             return true;  
  74.         return false;  
  75.     }  
  76.   
  77.     @Override  
  78.     public boolean hasRightTree() {  
  79.         if(rChild != null)  
  80.             return true;  
  81.         return false;  
  82.     }  
  83.   
  84.     @Override  
  85.     public boolean isEmpty() {  
  86.         if((lChild == null && rChild == null && data == null) || this == null) {  
  87.             return true;  
  88.         }  
  89.         return false;  
  90.     }  
  91.       
  92.     @Override  
  93.     public boolean isLeaf() {  
  94.         if(lChild == null && rChild == null) {  
  95.             return true;  
  96.         }  
  97.         return false;  
  98.     }  
  99.   
  100.     @Override  
  101.     public void removeLeftChild() {  
  102.         lChild = null;  
  103.     }  
  104.   
  105.     @Override  
  106.     public void removeRightChild() {  
  107.         rChild = null;  
  108.     }  
  109.     @Override  
  110.     public BTree root() {  
  111.         return this;  
  112.     }  
  113.     @Override  
  114.     public void setRootData(Object data) {  
  115.         this.data = data;  
  116.     }  
  117.     @Override  
  118.     public int size() {  
  119.         return size(this);  
  120.     }  
  121.     private int size(BTree btree) {  
  122.         if(btree == null)   
  123.             return 0;  
  124.         else if(btree.isLeaf())   
  125.             return 1;  
  126.         else {  
  127.             if(btree.getLeftChild() == null) {  
  128.                 return size(btree.getRightChild()) + 1;  
  129.             } else if(btree.getRightChild() == null) {  
  130.                 return size(btree.getLeftChild()) + 1;  
  131.             } else {  
  132.                 return size(btree.getLeftChild()) + size(btree.getRightChild()) + 1;  
  133.             }  
  134.         }   
  135.     }  
  136.       
  137.   
  138. }  


二叉树的遍历

 二叉树的遍历是指按照一定的次序访问树中所有结点,并且每个结点只被访问一次的过程。通常的遍历有三种方式,分别是:前序遍历、中序遍历和后序遍历,假设根结点、左孩子结点和右孩子结点分别用D、R、L表示,则前序遍历、中序遍历和后序遍历的顺序分别为DLR、LDR、LRD。所谓访问某结点,一般指对结点中的数据进行某种操作。所以,我们可以定义一个对结点中的数据进行操作的接口Visit,让所有遍历树的类实现这个接口。

Visit接口:

[java] view plaincopy
  1. package datastructure.tree;  
  2. /** 
  3.  * 对结点进行操作的接口 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public interface Visit {  
  8.     /** 
  9.      * 对结点进行某种操作 
  10.      * @param btree 树的结点 
  11.      */  
  12.     public void visit(BTree btree);  
  13. }  

遍历二叉树


[java] view plaincopy
  1. package datastructure.tree;  
  2. /** 
  3.  * 遍历二叉树 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public class OrderBTree implements Visit{  
  8.     /** 
  9.      * 前序遍历 
  10.      * @param root 根结点 
  11.      */  
  12.     public void preOrder(BTree root) {  
  13.         visit(root);  
  14.         if(root.getLeftChild() != null) {  
  15.             preOrder(root.getLeftChild());  
  16.         }  
  17.         if(root.getRightChild() != null) {  
  18.             preOrder(root.getRightChild());  
  19.         }  
  20.     }  
  21.     /** 
  22.      * 中序遍历 
  23.      * @param root 根结点 
  24.      */  
  25.     public void inOrder(BTree root) {  
  26.         if(root.getLeftChild() != null)  
  27.             inOrder(root.getLeftChild());  
  28.         visit(root);  
  29.         if(root.getRightChild() != null) {  
  30.             //System.out.println("true");  
  31.             inOrder(root.getRightChild());  
  32.         }  
  33.     }  
  34.     /** 
  35.      * 后序遍历 
  36.      * @param root 根结点 
  37.      */  
  38.     public void postOrder(BTree root) {  
  39.         if(root.getLeftChild() != null)  
  40.             postOrder(root.getLeftChild());  
  41.         if(root.getRightChild() != null)  
  42.             postOrder(root.getRightChild());  
  43.         visit(root);  
  44.     }  
  45.   
  46.     @Override  
  47.     public void visit(BTree btree) {  
  48.         System.out.print(btree.getRootData() + "\t");  
  49.     }  
  50.   
  51. }  

二叉树的测试


要构建的树

[java] view plaincopy
  1. package datastructure.tree;  
  2. /** 
  3.  * 测试二叉树 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public class BTreeTest {  
  8.     public static void main(String args[]) {  
  9.         BTree btree = new LinkBTree('A');  
  10.         BTree bt1, bt2, bt3, bt4;  
  11.         bt1 = new LinkBTree('B');  
  12.         btree.addLeftTree(bt1);  
  13.         bt2 = new LinkBTree('D');  
  14.         bt1.addLeftTree(bt2);  
  15.           
  16.         bt3 =  new LinkBTree('C');  
  17.         btree.addRightTree(bt3);  
  18.         bt4 =  new LinkBTree('E');  
  19.         bt3.addLeftTree(bt4);  
  20.         bt4 =  new LinkBTree('F');  
  21.         bt3.addRightTree(bt4);  
  22.           
  23.         System.out.println("树的深度:" + btree.dept());  
  24.         System.out.println("树的结点数:" + btree.size());  
  25.         System.out.println("是否为空树:" + btree.isEmpty());  
  26.         System.out.println("是否为叶子结点:" + btree.isLeaf());  
  27.         System.out.println("最左下边结点是否为叶子结点:" + btree.getRightChild().getRightChild().isLeaf());  
  28.         System.out.println("root结点:" + btree.root());  
  29.           
  30.         OrderBTree order = new OrderBTree();  
  31.         System.out.println("\n前序遍历:");  
  32.         order.preOrder(btree);  
  33.         System.out.println("\n中序遍历:");  
  34.         order.inOrder(btree);  
  35.         System.out.println("\n后序遍历:");  
  36.         order.postOrder(btree);  
  37.           
  38.         btree.removeLeftChild();  
  39.         System.out.println("\n删除左子树后中序遍历为:");  
  40.         order.inOrder(btree);  
  41.     }  
  42. }  

结果如下:

树的深度:3
树的结点数:6
是否为空树:false
是否为叶子结点:false
最左下边结点是否为叶子结点:true
root结点:datastructure.tree.LinkBTree@dc8569


前序遍历:
A B DCEF
中序遍历:
D B AECF
后序遍历:
D B EFCA
删除左子树后中序遍历为:
A E CF
原创粉丝点击