树的基本概念
1、树是一种数据结构,它是由n(n≥1)个有限结点组成一个具有层次关系的集合。
2、树Tree是n(n>=0)个结点的有限集。在任意一颗非空树中:
(1)有且仅有一个特定的被称为根root的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,...,Tm,其中每一个集合本身又是一棵树,并且称为根的子树SubTree.
1、结点拥有的子树数称为结点的度Degree。度为0的结点称为叶子Leaf或终端结点;度不为0的结点称为非终端结点或分支结点。
2、树的度是树内各结点度的最大值。
3、结点的子树的根称为该结点的孩子Child,相应地,该结点称为孩子的双亲结点Parent。
4、结点的层次Level是从根结点开始计算,根为第一层,根的孩子为第二层,依次类推。
树中结点的最大层次称为树的深度Depth或高度。
5、如果将树中结点的各子树看成从左至右是有次序的(即不能互换),则该树称为有序树,否则称为无序树。
二叉树的基本概念
1、二叉树Binary Tree的特点是每个结点至多具有两棵子树(即在二叉树中不存在度大于2 的结点),并且子树之间有左右之分。
它有五种基本形态:二叉树可以是空集;根可以有空的左子树或右子树;或者左、右子树皆为空。
2、二叉树Binary Tree性质:
1、在二叉树的第i层至多有2^(i-1)个结点(i≥1);
2、深度为k的二叉树至多有2^k-1个结点(k≥1);
3、对任意一棵二叉树,如果其终端结点数为n0,度为2 的结点数为n2,则,n0=n2+1
4、具有n个结点的完全二叉树的深度不大于log2 n的最大整数加1
5、包含n个结点的二叉树的高度至少为log2 (n+1)
6、如果对一棵有n个结点的完全二叉树的结点按层序编号(从第一层到最后一层,每层从左到右),则对任一结点(1≤i≤n),有
a:如果i=1,则结点i是二叉树的根,无双亲;
如果i>1,则其双亲是结点x(其中结点x是 不大于i/2的最大整数)
b:如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
c:如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1
3、满二叉树、完全二叉树和二叉查找树
3.1满二叉树
定义:高度为h,并且由2{h} –1个结点的二叉树,被称为满二叉树。
3.2完全二叉树
定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下一层的叶结点集中在靠左的若干位置上。这样的二叉树称为完全二叉树。
特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。
3.3二叉查找树
定义:二叉查找树(Binary Search Tree),又被称为二叉搜索树。设x为二叉查找树中的一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。
二叉查找树(BinarySearch Tree,也叫二叉搜索树,或二叉排序树BinarySort Tree)或者是一棵空树,或者是具有下列性质的二叉树:
1、若任意结点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2、若任意结点的右子树不空,则右子树上所有节点的值均大于它的根结点的值;
3、任意结点的左右子树也分别为二叉查找树;
4、没有键值相等的结点。
在实际应用中,二叉查找树的使用比较多。
二叉查找树的Java实现
1、二叉查找树结点的定义
BSTree是二叉树,它保护了二叉树的根结点mRoot;mRoot是BSTNode类型,而BSTNode是二叉查找树的结点,它是BSTree的内部类。二叉查找树的节点BSTNode包含二叉查找树的几个基本信息:
(01) key -- 它是关键字,是用来对二叉查找树的节点进行排序的。(02) left -- 它指向当前节点的左孩子。
(03) right -- 它指向当前节点的右孩子。
(04) parent -- 它指向当前节点的父结点。
package binarySearchTree; public class BSTree<T extends Comparable<T>> { private BSTNode<T> mRoot; //根结点 public class BSTNode<T extends Comparable<T>>{ //内部类 T key; //关键字 BSTNode<T> left; //左孩子 BSTNode<T> right; //右孩子 BSTNode<T> parent; //父结点 public BSTNode(T key, BSTNode<T> left, BSTNode<T> right, BSTNode<T> parent) { super(); this.key = key; this.left = left; this.right = right; this.parent = parent; } } }
2、遍历
2.1前序遍历
若二叉树非空,则执行以下操作:
(01)访问根节点
(02)先序遍历左子树
(03)先序遍历右子树
/** * 前序遍历二叉树 */ public void preOrder(){ preOrder(mRoot); } private void preOrder(BSTNode<T> tree){ if (tree!=null) { System.out.println(tree.key+" "); preOrder(tree.left); preOrder(tree.right); } }
2.2中序遍历
若二叉树非空,则执行以下操作:
(01)中序遍历左子
(02)树访问根节点
(03)中序遍历右子树
/** * 中序遍历二叉树 */ public void inOrder(){ inOrder(mRoot); } private void inOrder(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree!=null) { inOrder(tree.left); System.out.println(tree.key+" "); inOrder(tree.right); } }
2.3后序遍历
若二叉树非空,则执行以下操作:
(01)后序遍历左子树
(02)后序遍历右子树
(03)访问根节点
/** * 后序遍历二叉树 */ public void postOrder(){ postOrder(mRoot); } private void postOrder(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree!=null) { postOrder(tree.left); postOrder(tree.right); System.out.println(tree.key+" "); } }
3、查找
递归版本的代码
/** * 查找 * 递归实现 查找二叉树tree中键值为key的结点 */ public BSTNode<T> search(T key){ return search(mRoot,key); } private BSTNode<T> search(BSTNode<T> tree, T key) { // TODO Auto-generated method stub if (tree==null) { return tree; } int cmp=key.compareTo(tree.key); if (cmp<0) { return search(tree.left, key); }else if (cmp>0) { return search(tree.right, key); }else { return tree; } }
非递归版本的代码
/** * 查找 * 非递归实现 查找二叉树tree中键值为key的结点 */ public BSTNode<T> iterSearch(T key){ return iterSearch(mRoot,key); } private BSTNode<T> iterSearch(BSTNode<T> tree, T key) { // TODO Auto-generated method stub while(tree!=null){ int cmp=key.compareTo(tree.key); if (cmp<0) { tree=tree.left; }else if (cmp>0) { tree=tree.right; }else { return tree; } } return tree; }
4、最大值和最小值
查找最大值的代码
/** * 查找最大结点:返回tree为根结点的二叉树的最大结点 */ public T max(){ BSTNode<T> p=max(mRoot); if (p!=null) { return p.key; } return null; } private BSTNode<T> max(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return null; } while(tree.right!=null){ tree=tree.right; } return tree; }
查找最小值的代码
/** * 查找最小结点:返回tree为根结点的二叉树的最小结点 */ public T min(){ BSTNode<T> p=min(mRoot); if (p!=null) { return p.key; } return null; } private BSTNode<T> min(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return null; } while(tree.left!=null){ tree=tree.left; } return tree; }
5、前驱和后继
结点的前驱:是该结点的左子树中的最大结点。
结点的后继:是该结点的右子树中的最小结点。
查找前驱结点的代码
/** * 找结点x的前驱结点:即,查找“二叉树中数据值小于该结点”的“最大结点” */ public BSTNode<T> predecessor(BSTNode<T> x){ //如果x存在左孩子,则“x的前驱结点”为“以其左孩子为根的子树的最大结点” if (x.left!=null) { return max(x.left); } /** * 如果x没有左孩子,则x有以下两种可能 * 1、x是“一个右孩子”,则“x的前驱结点”为“它的父结点” * 2、x是“一个左孩子”,则查找“x的最低的父结点,并且该父结点要具有右孩子”, * 找到的这个“最低的父结点”就是“x的前驱结点” */ BSTNode<T> y=x.parent; while((y!=null)&&(x==y.left)){ x=y; y=y.parent; } return y; }
查找后继结点的代码
/** * 找结点x的后继结点:即,查找“二叉树中数据值大于该结点”的“最小结点” */ public BSTNode<T> successor(BSTNode<T> x){ //如果x存在右孩子,则“x的后继结点”为“以其右孩子为根的子树的最小结点” if (x.right!=null) { return min(x.right); } /** * 如果x没有右孩子,则x有以下两种可能 * 1、x是“一个左孩子”,则“x的后继结点”为“它的父结点” * 2、x是“一个右孩子”,则查找“x的最低的父结点,并且该父结点要具有左孩子”, * 找到的这个“最低的父结点”就是“x的后继结点” */ BSTNode<T> y=x.parent; while((y!=null)&&(x==y.right)){ x=y; y=y.parent; } return y; }
6、插入
先找到待插入的叶子结点,再在叶子结点上判断与key的关系,以判断key值应该插入到什么位置
插入结点的代码
/** * 新建结点key,并将其插入到二叉树中 * @param bst 二叉树 * @param key 插入结点的键值 * @param z 插入的结点 */ public void insert(T key){ BSTNode<T> z=new BSTNode<T>(key, null, null, null); //如果新建结点失败,则返回 if (z!=null) { insert(this,z); } } private void insert(BSTree<T> bst, BSTNode<T> z) { // TODO Auto-generated method stub int cmp; BSTNode<T> y=null; BSTNode<T> x=bst.mRoot;//x指向该树的根结点 /* * 查找z的插入位置 * 比较根结点x与新节点z之间的关系 * 这时,y结点指向根结点x,若z小于根结点,则x指向x的左子树;否则指向右子树 * 直到左/右子树为空 【y结点是x结点的父结点】 * 此时,z.parent指向y * if y=null * 新节点z就是父结点; * else * 比较z和y的大小, * if z<y * z插入到y的左孩子的位置 * else * z插入到y的右孩子的位置 */ while(x!=null){ y=x; cmp=z.key.compareTo(x.key); if (cmp<0) { x=x.left; }else { x=x.right; } } z.parent=y; if (y==null) { bst.mRoot=z; }else { cmp=z.key.compareTo(y.key); if (cmp<0) { y.left=z; }else { y.right=z; } } }
7、删除
删除结点的代码
/** * 删除结点z,并返回被删除的结点 * @param tree 二叉树的根结点 * @param z 删除的结点 */ public void remove(T key){ BSTNode<T> z,node; if ((z=search(mRoot, key))!=null) { if ((node=remove(this,z))!=null) { node=null; } } } /** * 删除结点z,并返回被删除的结点 * @param bst 二叉树 * @param z 删除的结点 */ private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) { // TODO Auto-generated method stub BSTNode<T> x=null;//子结点child BSTNode<T> y=null;//真正删除的结点 //只有一个结点或没有结点时 if ((z.left==null) ||(z.right==null)) { y=z;//z就是要删除的结点 }else{ y=successor(z);//当有两个子结点时,删除后继结点 } //获取子结点,不管左右 if (y.left!=null) { x=y.left; }else{ x=y.right; } //如果存在子结点,就关联被删除结点的父结点 if (x!=null) { x.parent=y.parent; } //如果父结点是空,说明要删的是根结点 if (y.parent==null) { bst.mRoot=x;//设置根为child(此时根只有一个结点或者没有结点) }else if (y==y.parent.left.left) {//要删的是左结点 y.parent.left=x;//左结点关联子结点 }else {//要删除的是右结点 y.parent.right=x;//右结点关联子结点 } //如果要删除的结点和一开始传入的不一样,就是后继情况 if (y!=z) { z.key=y.key;//后继的值传给本来要删除的结点 } return y;//返回被删除的结点 }
总结删除结点的思路 delete方法 1、如果该结点同时存在左右子结点 获取后继结点; 转移后继结点值到当前结点node; 把要删除的当前结点设置为后继结点successor。 2、经过步骤1的处理,下面两种情况,只能是一个结点或者没有结点。 不管有没有结点,都获取子结点child if child!=null,就说明有一个结点的情况,此时将父结点与子结点关联上 if 当前结点没有父结点(后继情况到这一定有父结点),说明要删除的就是根结点, 根结点设置为child else if 当前结点是父结点的左结点 则将父结点的左结点设置为child else 当前结点是父结点的右结点 则将父结点的右结点设置为child 3、返回被删除的结点node
public void delete(T key){ //获取要删除的结点 BSTNode<T> node=search(mRoot, key); //如果存在就删除 if (node!=null) { delete(node); } } private BSTNode<T> delete(BSTNode<T> node) { //第3种情况,如果同时存在左右子结点 if (node.left!=null && node.right!=null) { //获取后继结点 BSTNode<T> successor=successor(node); //转移后继结点值到当前结点 node.key=successor.key; //把要删除的当前结点设置为后继结点 node=successor; } /** * 经过前一步处理,下面只有两种情况,只能是一个结点或者没有结点 * 不管是否有子结点,都获取子结点 */ BSTNode<T> child; if (node.left!=null) { child=node.left; }else{ child=node.right; } /** * 如果child!=null,就说明有一个结点的情况 * 将父结点与子结点关联上 */ if (child!=null) { child.parent=node.parent; } /** * 如果当前结点没有父结点(后继情况到这儿时一定有父结点) * 说明要删除的就是根结点 */ if (node.parent==null) { /** * 根结点设置为子结点 * 按照前面的逻辑,根只有一个或者没有结点,所以直接赋child */ mRoot=child; }else if (node==node.parent.left) { /** * 存在父结点,并且当前结点是左结点 * 将父结点的左结点设置为child */ node.parent.left=child; }else { /** * 存在父结点,并且当前结点是右结点 * 将父结点的右结点设置为child */ node.parent.right=child; } //返回被删除的结点 return node; }
8、打印
打印二叉查找树的代码
/** * 打印二叉查找树 * key: 结点的值 * i : 0,表示该结点是根结点 * -1,表示该结点是它的父结点的左孩子 * 1,表示该结点是它的父结点的右孩子 */ public void print(){ if (mRoot!=null) { print(mRoot,mRoot.key,0); } } private void print(BSTNode<T> tree, T key, int i) { // TODO Auto-generated method stub if (tree!=null) { if (i==0) {//根结点 System.out.printf("%2d is root\n",tree.key); }else { System.out.printf("%2d is %2d's %6s child\n",tree.key,key, i==1?"right":"left"); } print(tree.left, tree.key, -1); print(tree.right, tree.key, 1); } }
9、销毁
销毁二叉查找树的代码
/** * 销毁二叉树 */ public void clear(){ destory(mRoot); mRoot=null; } private void destory(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return ; } if (tree.left!=null) { destory(tree.left); } if (tree.right!=null) { destory(tree.right); } tree=null; }
实现二叉查找树的完整代码
package binarySearchTree; public class BSTree<T extends Comparable<T>> { private BSTNode<T> mRoot; //根结点 public class BSTNode<T extends Comparable<T>>{ //内部类 T key; //关键字 BSTNode<T> left; //左孩子 BSTNode<T> right; //右孩子 BSTNode<T> parent; //父结点 //通过构造方法初始化结点 public BSTNode(T key, BSTNode<T> left, BSTNode<T> right, BSTNode<T> parent) { super(); this.key = key; this.left = left; this.right = right; this.parent = parent; } public T getKey(){ return key; } @Override public String toString() { // TODO Auto-generated method stub return "key:"+key; } } public BSTree() { mRoot=null; } /** * 新建结点key,并将其插入到二叉树中 * @param bst 二叉树 * @param key 插入结点的键值 * @param z 插入的结点 */ public void insert(T key){ BSTNode<T> z=new BSTNode<T>(key, null, null, null); //如果新建结点失败,则返回 if (z!=null) { insert(this,z); } } private void insert(BSTree<T> bst, BSTNode<T> z) { // TODO Auto-generated method stub int cmp; BSTNode<T> y=null; BSTNode<T> x=bst.mRoot;//x指向该树的根结点 /* * 查找z的插入位置 * 比较根结点x与新节点z之间的关系 * 这时,y结点指向根结点x,若z小于根结点,则x指向x的左子树;否则指向右子树 * 直到左/右子树为空 【y结点是x结点的父结点】 * 此时,z.parent指向y * if y=null * 新节点z就是父结点; * else * 比较z和y的大小, * if z<y * z插入到y的左孩子的位置 * else * z插入到y的右孩子的位置 */ while(x!=null){ y=x; cmp=z.key.compareTo(x.key); if (cmp<0) { x=x.left; }else { x=x.right; } } z.parent=y; if (y==null) { bst.mRoot=z; }else { cmp=z.key.compareTo(y.key); if (cmp<0) { y.left=z; }else { y.right=z; } } } /** * 前序遍历二叉树 */ public void preOrder(){ preOrder(mRoot); } private void preOrder(BSTNode<T> tree){ if (tree!=null) { System.out.println(tree.key+" "); preOrder(tree.left); preOrder(tree.right); } } /** * 中序遍历二叉树 */ public void inOrder(){ inOrder(mRoot); } private void inOrder(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree!=null) { inOrder(tree.left); System.out.println(tree.key+" "); inOrder(tree.right); } } /** * 后序遍历二叉树 */ public void postOrder(){ postOrder(mRoot); } private void postOrder(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree!=null) { postOrder(tree.left); postOrder(tree.right); System.out.println(tree.key+" "); } } /** * 查找 * 递归实现 查找二叉树tree中键值为key的结点 */ public BSTNode<T> search(T key){ return search(mRoot,key); } private BSTNode<T> search(BSTNode<T> tree, T key) { // TODO Auto-generated method stub if (tree==null) { return tree; } int cmp=key.compareTo(tree.key); if (cmp<0) { return search(tree.left, key); }else if (cmp>0) { return search(tree.right, key); }else { return tree; } } /** * 查找 * 非递归实现 查找二叉树tree中键值为key的结点 */ public BSTNode<T> iterSearch(T key){ return iterSearch(mRoot,key); } private BSTNode<T> iterSearch(BSTNode<T> tree, T key) { // TODO Auto-generated method stub while(tree!=null){ int cmp=key.compareTo(tree.key); if (cmp<0) { tree=tree.left; }else if (cmp>0) { tree=tree.right; }else { return tree; } } return tree; } /** * 查找最小结点:返回tree为根结点的二叉树的最小结点 */ public T min(){ BSTNode<T> p=min(mRoot); if (p!=null) { return p.key; } return null; } private BSTNode<T> min(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return null; } while(tree.left!=null){ tree=tree.left; } return tree; } /** * 查找最大结点:返回tree为根结点的二叉树的最大结点 */ public T max(){ BSTNode<T> p=max(mRoot); if (p!=null) { return p.key; } return null; } private BSTNode<T> max(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return null; } while(tree.right!=null){ tree=tree.right; } return tree; } /** * 找结点x的前驱结点:即,查找“二叉树中数据值小于该结点”的“最大结点” */ public BSTNode<T> predecessor(BSTNode<T> x){ //如果x存在左孩子,则“x的前驱结点”为“以其左孩子为根的子树的最大结点” if (x.left!=null) { return max(x.left); } /** * 如果x没有左孩子,则x有以下两种可能 * 1、x是“一个右孩子”,则“x的前驱结点”为“它的父结点” * 2、x是“一个左孩子”,则查找“x的最低的父结点,并且该父结点要具有右孩子”, * 找到的这个“最低的父结点”就是“x的前驱结点” */ BSTNode<T> y=x.parent; while((y!=null)&&(x==y.left)){ x=y; y=y.parent; } return y; } /** * 找结点x的后继结点:即,查找“二叉树中数据值大于该结点”的“最小结点” */ public BSTNode<T> successor(BSTNode<T> x){ //如果x存在右孩子,则“x的后继结点”为“以其右孩子为根的子树的最小结点” if (x.right!=null) { return min(x.right); } /** * 如果x没有右孩子,则x有以下两种可能 * 1、x是“一个左孩子”,则“x的后继结点”为“它的父结点” * 2、x是“一个右孩子”,则查找“x的最低的父结点,并且该父结点要具有左孩子”, * 找到的这个“最低的父结点”就是“x的后继结点” */ BSTNode<T> y=x.parent; while((y!=null)&&(x==y.right)){ x=y; y=y.parent; } return y; } /** * 删除结点z,并返回被删除的结点 * @param tree 二叉树的根结点 * @param z 删除的结点 */ public void remove(T key){ BSTNode<T> z,node; if ((z=search(mRoot, key))!=null) { if ((node=remove(this,z))!=null) { node=null; } } } /** * 删除结点z,并返回被删除的结点 * @param bst 二叉树 * @param z 删除的结点 */ private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) { // TODO Auto-generated method stub BSTNode<T> x=null;//真正删除结点的子树;左右子树合体的抽象 BSTNode<T> y=null;//真正删除的结点 //获取真正删除的结点 if ((z.left==null) ||(z.right==null)) { y=z; }else{ y=successor(z); } //真正删除结点的子树;左右子树合体的抽象 if (y.left!=null) { x=y.left; }else{ x=y.right; } //删除 真正删除结点 if (x!=null) { x.parent=y.parent; } //删除之后把子树这段了,准备焊接 if (y.parent==null) { bst.mRoot=x; }else if (y==y.parent.left.left) { y.parent.left=x; }else { y.parent.right=x; } //对删除转移 做值替换 if (y!=z) { z.key=y.key; } return y; } public void delete(T key){ //获取要删除的结点 BSTNode<T> node=search(mRoot, key); //如果存在就删除 if (node!=null) { delete(node); } } private BSTNode<T> delete(BSTNode<T> node) { //第3种情况,如果同时存在左右子结点 if (node.left!=null && node.right!=null) { //获取后继结点 BSTNode<T> successor=successor(node); //转移后继结点值到当前结点 node.key=successor.key; //把要删除的当前结点设置为后继结点 node=successor; } /** * 经过前一步处理,下面只有两种情况,只能是一个结点或者没有结点 * 不管是否有子结点,都获取子结点 */ BSTNode<T> child; if (node.left!=null) { child=node.left; }else{ child=node.right; } /** * 如果child!=null,就说明有一个结点的情况 * 将父结点与子结点关联上 */ if (child!=null) { child.parent=node.parent; } /** * 如果当前结点没有父结点(后继情况到这儿时一定有父结点) * 说明要删除的就是根结点 */ if (node.parent==null) { /** * 根结点设置为子结点 * 按照前面的逻辑,根只有一个或者没有结点,所以直接赋child */ mRoot=child; }else if (node==node.parent.left) { /** * 存在父结点,并且当前结点是左结点 * 将父结点的左结点设置为child */ node.parent.left=child; }else { /** * 存在父结点,并且当前结点是右结点 * 将父结点的右结点设置为child */ node.parent.right=child; } //返回被删除的结点 return node; } /** * 打印二叉查找树 * key: 结点的值 * i : 0,表示该结点是根结点 * -1,表示该结点是它的父结点的左孩子 * 1,表示该结点是它的父结点的右孩子 */ public void print(){ if (mRoot!=null) { print(mRoot,mRoot.key,0); } } private void print(BSTNode<T> tree, T key, int i) { // TODO Auto-generated method stub if (tree!=null) { if (i==0) {//根结点 System.out.printf("%2d is root\n",tree.key); }else { System.out.printf("%2d is %2d's %6s child\n",tree.key,key, i==1?"right":"left"); } print(tree.left, tree.key, -1); print(tree.right, tree.key, 1); } } /** * 销毁二叉树 */ public void clear(){ destory(mRoot); mRoot=null; } private void destory(BSTNode<T> tree) { // TODO Auto-generated method stub if (tree==null) { return ; } if (tree.left!=null) { destory(tree.left); } if (tree.right!=null) { destory(tree.right); } tree=null; } }
二叉查找树的测试程序
package binarySearchTree; public class BSTreeTest { private static final int arr[]={1,5,4,3,2,6}; public static void main(String[] args) { // TODO Auto-generated method stub BSTree<Integer> tree=new BSTree<>(); System.out.println("==依次添加:"); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); tree.insert(arr[i]); } System.out.println("==前序遍历:"); tree.preOrder(); System.out.println("==中序遍历:"); tree.inOrder(); System.out.println("==后序遍历:"); tree.postOrder(); System.out.println("++++遍历树++++"); tree.print(); System.out.println("==最小值:"+tree.min()); System.out.println("==最大值:"+tree.max()); //System.out.println("==删除根结点:"+arr[3]); //tree.remove(arr[3]); System.out.println("==中序遍历:"); tree.inOrder(); //销毁二叉树 tree.clear(); } }