泛型的二叉搜索树,请指点
泛型的二叉搜索树,请指点小弟初学java,写了一个泛型的二叉搜索树(源代码见后)。
IBSTree接口定义一个二叉搜索树的对外接口,这个接口描述了二叉搜索树的所有对外可见的行为。具体的方法描述见源代码的注释。
IBSTree接口中有定义了一个二叉搜索树的节点类型的接口IBSTNode(这个接口也可以在IBSTree接口的外部定义,只是这个接口太小,个人觉得没必要单独定义),
这个接口描述了二叉搜索树的一个节点的对外可以的部分(对外只是可以获取节点的值)。
然后再定义了两个类BSTNode和BSTree,分别实现了这两个接口。
这个设计有点复杂,自己都觉得不够清爽^-^,
定义IBSNode纯粹是考虑到实现的效率,返回一个IBSNode的类可以传达更多的节点信息,尽管这些信息对外不可见,但是内部实现需要这些信息。
二叉搜索树的各个操作的实现没有做注释^-^,是由于这些操作在任何一本数据结构的书上都有详细的说明。
小弟主要关注的是泛型和程序的整个结构。
请各位路过的大虾指点一下,小弟万分感激。^-^
小弟初来,没多少分,^-^
源文件共三个:IBSTree.java、BSTNode.java、BSTree.java。
文件1:IBSTree.java
package BinarySearchTree;
//二叉搜索树类型
public interface IBSTree <Value extends Comparable <Value> > {
public interface IBSTNode <Value> {
Value getValue(); //获取二叉搜索树结点的键
boolean isEmpty(); //判断二叉搜索树结点是否为空
}
void makeEmptyBST(); //创建一棵空的二叉搜索树
boolean isEmptyBST(); //判断一棵二叉搜索树是否为空
IBSTNode <Value> search(Value k); //在二叉树搜索树中查找指定的键
boolean insert(Value k); //向二叉搜索树中插入键
IBSTNode <Value> getMax(); //获取二叉搜索树中的最大值
IBSTNode <Value> getMin(); //获取二叉搜索树中的最小值
IBSTNode <Value> succ(IBSTNode <Value> n); //获取后继
IBSTNode <Value> pred(IBSTNode <Value> n); //获取前驱
boolean delete(IBSTNode <Value> n); //删除二叉搜索树中的指定元素
}
文件2:BSTNode.java
package BinarySearchTree;
/**
*BSTNode类表示二叉搜索树的一个结点。
*BSTNode的值可以是:
* 1、EMPTY。表示这是一个空结点。
* 2、(key,left,right,parent)。其中key表示结点值,left表示左子树,right表示右子树,parent表示父节点。
*Value类型是一种实现了Comparable接口的类型。
*/
public final class BSTNode <Value extends Comparable <Value> >
implements IBSTree.IBSTNode <Value> {
public Value getValue() { //获取二叉搜索树结点的键
if (this==EMPTY) return null;
else return this.key;
}
public boolean isEmpty() { //判断二叉搜索树结点是否为空
if (this==EMPTY) return true;
else return false;
}
static final BSTNode EMPTY=new BSTNode(null,null,null,null); //表示空的二叉树节点
BSTNode <Value> left;
BSTNode <Value> right;
BSTNode <Value> parent;
Value key;
BSTNode(Value key,BSTNode <Value> left,
BSTNode <Value> right,BSTNode <Value> parent) {
this.key=key;
this.left=left;
this.right=right;
this.parent=parent;
}
}
文件3:BSTree.java
package BinarySearchTree;
/**
*BSTree类表示二叉搜索树。
*Value类型是一种实现了Comparable接口的类型。
*/
public final class BSTree <Value extends Comparable <Value> >
implements IBSTree <Value> {
public void makeEmptyBST() {//创建一棵空的二叉搜索树
root=BSTNode.EMPTY;
}
public boolean isEmptyBST() {//判断二叉搜索树结点是否为空
if (root==BSTNode.EMPTY) return true;
else return false;
}
public IBSTNode <Value> getMax() {//获取二叉搜索树中的最大值
if (root==BSTNode.EMPTY) return BSTNode.EMPTY;
else {
BSTNode <Value> p=root;
while ((p!=BSTNode.EMPTY)&&(p.right!=BSTNode.EMPTY))
p=p.right;
return p;
}
}
public IBSTNode <Value> getMin() {//获取二叉搜索树中的最小值
if (root==BSTNode.EMPTY) return BSTNode.EMPTY;
else {
BSTNode <Value> p=root;
while ((p!=BSTNode.EMPTY)&&(p.left!=BSTNode.EMPTY))
p=p.left;
return p;
}
}
public IBSTNode <Value> search(Value k) {//在二叉树搜索树中查找指定的键
BSTNode <Value> p=root;
while ((p!=BSTNode.EMPTY)&&(p.key.compareTo(k)!=0))
if (k.compareTo(p.key) <0) p=p.left;
else p=p.right;
return p;
}
public boolean insert(Value k) {//向二叉搜索树中插入键
if (root==BSTNode.EMPTY) {
root=new BSTNode <Value> (k,BSTNode.EMPTY,
BSTNode.EMPTY,BSTNode.EMPTY);
return true;
} else {
BSTNode <Value> p=root;
BSTNode <Value> q=root;
while ((p!=BSTNode.EMPTY)&&(p.key.compareTo(k)!=0))
if (k.compareTo(p.key) <0) {
q=p;
p=p.left;
} else {
q=p;
p=p.right;
};
if (p==BSTNode.EMPTY) {
p=new BSTNode <Value> (k,BSTNode.EMPTY,
BSTNode.EMPTY,BSTNode.EMPTY);
if (k.compareTo(q.key) <0) q.left=p;
else q.right=p;
return true;
} else return false;
}
}
public IBSTNode <Value> succ(IBSTNode <Value> n) {//获取后继
if (!(n instanceof BSTNode)) return BSTNode.EMPTY;
BSTNode <Value> m;
m=(BSTNode <Value> ) n;
if (m==BSTNode.EMPTY) return BSTNode.EMPTY;
else {
if (m.right!=BSTNode.EMPTY) {
BSTree <Value> p=new BSTree <Value> (m.right);
return p.getMin();
} else {
BSTNode <Value> p=m;
BSTNode <Value> q=p.parent;
while ((q!=BSTNode.EMPTY)&&(q.right==p)) {
p=q;
q=p.parent;
}
if (q==BSTNode.EMPTY) return BSTNode.EMPTY;
else return q;
}
}
}
public IBSTNode <Value> pred(IBSTNode <Value> n) {//获取前驱
if (!(n instanceof BSTNode)) return BSTNode.EMPTY;
BSTNode <Value> m;
m=(BSTNode <Value> ) n;
if (m==BSTNode.EMPTY) return BSTNode.EMPTY;
else {
if (m.left!=BSTNode.EMPTY) {
BSTree <Value> p=new BSTree <Value> (m.left);
return p.getMax();
} else {
BSTNode <Value> p=m;
BSTNode <Value> q=p.parent;
while ((q!=BSTNode.EMPTY)&&(q.left==p)) {
p=q;
q=p.parent;
}
if (q==BSTNode.EMPTY) return BSTNode.EMPTY;
else return q;
}
}
}
public boolean delete(IBSTNode <Value> n) {//删除二叉搜索树中的指定元素 ,没实现
return true;
}
private BSTNode <Value> root;
private BSTree(BSTNode <Value> root){
this.root=root;
}
}
[解决办法]
怎么说呢?可以说你的代码没什么错,因为它可以实现需要的功能;但也可以说,你的代码完全错了,因为它完全不像Java编程的方式,更像从C或C++“翻译”过来的。
我提几点供你参考:
首先,你的接口没什么存在的必要,因为它只有一个实现类,而且如果你的实现类已经实现了所有功能,别人没有理由按你定义的接口再去实现一个。
我想楼主是模仿C++中的做法,把类的接口都定义到头文件中,具体实现放到类实现文件中;但在Java中没有必要这样做。因为Java编译器会自动搜索现存的其它类,不需要一个类似于C++中的头文件那样的“中介”。换句话说,接口的“中介”作用是在运行时体现的,不是为了编译。
第二,你没有充分利用面向对象的特性,比如makeEmptyXXX()这样的接口,很容易让人联想到古老的C语言教程上的代码。
把初始化工作放到构造方法中,再设置一个用来执行清空动作的empty()方法(如果需要的话),这种作法更合理。
第三,二叉检索树是递归定义的,根据这个递归定义,很容易得到,一棵二叉检索树的左右子树(如果有的话)分别各是一棵二叉检索树。
再加上你的类是泛型的,泛型的类型就是节点的类型,所以,Node这个类没有什么存在的必要,换句话说,Node本身就是二叉检索树,二者可以合而为一。
第四,代码风格上的问题。
命名不是很符合Java的惯例,比如,包名应该从简,并且完全小写,而类名应该尽量详细并带有自说明性,一般不简写;Java的接口名一般不带字母“I”的前缀。当然这些不是什么大问题。
根据上面的几点考虑,我整理的代码如下:
(我的方法是递归的,递归的程序逻辑更清晰,当然,如果基于效率的考虑,不应该滥用递归;不过,仍旧可以先用递归方式设计出基本功能,再去对细部进行优化;
删除节点方法比较复杂,未实现)
package bst;public final class BinarySearchTree <T extends Comparable <T> > { private T value; private BinarySearchTree<T> parent; private BinarySearchTree<T> left, right; public boolean isEmpty() { return value == null; } public boolean insert(T newValue) { if (isEmpty()) { //如果是空树,则直接对value赋值,并初始化左右子树 value = newValue; left = new BinarySearchTree <T> (); right = new BinarySearchTree <T> (); left.parent = right.parent = this; return true; } if (newValue.compareTo(value) > 0) // 如果插入的值大于当前值,插在右子树中 return right.insert(newValue); else if (newValue.compareTo(value) < 0) // 如果插入的值小于当前值,插在左子树中 return left.insert(newValue); return false; // 节点已存在,插入失败 } public boolean delete(T val) { // 未实现 } public T search(T val) { if (!isEmpty()) { if (val.compareTo(value) > 0) // 如果待检索值大于当前值,检索右子树 return right.search(val); else if (val.compareTo(value) < 0) // 如果待检索值小于当前值,检索左子树 return left.search(val); else return value; // 检索成功,返回当前值 } return null; // 检索失败,返回null } public T getMin() { if (left.isEmpty()) // 如果左子树为空,则当前值最小 return value; return left.getMin(); // 从左子树中找最小值 } public T getMax() { if (right.isEmpty()) // 如果右子树为空,则当前值最大 return value; return right.getMax(); // 从右子树中找最大值 } public String toString() { // 显示该树,该方法可选 StringBuffer result = new StringBuffer(); if (!isEmpty()) { result.append(value); if (!left.isEmpty() || !right.isEmpty()) { result.append('('); result.append(left); result.append(','); result.append(right); result.append(')'); } } else result.append('*'); return result.toString(); }}