完整实例的GitHub地址
https://github.com/lvxixiao/DSA
顺序性
任一节点r的左(右)子树中,所有节点均小于(大于)r。
中序遍历序列
任何一棵二叉搜索树,其中序遍历序列单调非降。
查找算法及其实现
二叉搜索树的查找算法,采用减而治之的思路与策略,其执行过程可以描述为:从树根触发,逐步地缩小查找范围,直到发现目标(成功)或缩小至空树(失败)。
public BinNode<T> search(T e) {
return searchIn(root,e);
}
private BinNode<T> searchIn(BinNode<T> v, T e) {
if(v==null || v.getData()==e)//递归基,假想在节点v处命中
return v;
this.hot = v;
return v.getData().compareTo(e)<0?searchIn(v.getRc(), e):searchIn(v.getLc(),e);
}//返回时,返回值指向命中节点,hot指向其父亲。
插入算法及其实现
为了在二叉搜索树中插入一个节点,首先需要利用查找算法确定插入的位置及方向,然后才能将新节点作为叶子插入。
首先调用search()查找e。若返回位置x非空,则说明已有雷同节点,插入失败。否则x必是hot节点的某一空孩子,于是创建这个孩子并存入e。
//插入
public boolean insert(T e) {
BinNode<T> x = search(e);
//默认不存在重复元素
if(x!=null)
return false;
//创建新节点,search(e)后确定的hot为其父亲。
x = new BinNode<T>(e,this.hot, null, null);
if(this.hot.getData().compareTo(e) < 0) {
this.hot.setRc(x);
} else {
this.hot.setLc(x);
}
return true;
}
删除算法及其实现
为从二叉搜索树中删除节点,首先需要调用搜索算法,判断目标节点是否存在于树中,若存在,则需返回其位置,然后相应的实施删除操作。
单分支情况
对于待删除节点仅仅拥有左孩子的情况,只需要将其替换为左孩子,然后令其左孩子为Null,删除操作便完成了。对称的仅有右孩子的情况,操作类似。
双分支情况。
对于左右孩子都存在的情况,需要找到该节点的直接后继,然后只需要交换二者的数据项,则可将后继节点等效视作待删除的目标节点。
删除算法代码
//删除
public boolean remove(T e) {
BinNode<T> x = search(e);
if(x==null)
return false;
removeAt(x);
return true;
}
private void removeAt(BinNode<T> x) {
BinNode<T> w = x;//实际被摘除的节点,初值等于x
BinNode<T> succ = null;//实际被删除节点的接替者
boolean isLeftChild = true;//用来确定待删除节点是父亲节点的左孩子还是右孩子
if( !x.hasLChild() )//如果左子树为空
{
succ = x.getRc();
x = x.getRc();
} else if(!x.hasRChild()){ //如果右子树为空
succ = x.getLc();
x = x.getLc();
} else { //左右子树都存在
w = w.succ();
swap(x,w);
BinNode<T> u = w.getParent();
succ = w.getRc();
if(u==x) {
u.setRc(succ);
} else {
u.setLc(succ);
}
}
this.hot = w.getParent();
if(hot!=null) {
if(hot.getData().compareTo(w.getData())<0) {
isLeftChild=false;
} else {
isLeftChild=true;
}
//判断是否有接替者
if(succ!=null) {
//建立双向连接,隔离被删除节点
if(isLeftChild) {
hot.setLc(succ);
} else {
hot.setRc(succ);
}
succ.setParent(hot);
} else {
if(isLeftChild) {
hot.removeLc();
} else {
hot.removeRc();
}
}
}
}
public class BinNode<T extends Comparable<T>> {
private T data;
private BinNode<T> parent;
private BinNode<T> lc;
private BinNode<T> rc;
//取当前节点的直接后继
public BinNode<T> succ() {
BinNode<T> s = this;
//如果有右孩子,直接后继必在右子树中最靠左的节点
if(s.getRc()!=null) {
s = getRc();
while(s.hasLChild())
s = s.getLc();
} else {
//如果没有右孩子,直接后继位于“将当前节点包含于其左子树中的最低祖先”
while(s.isRChild())
s = s.getParent();
s = s.getParent();
}
return s;
}
}