其实该二叉查找树的写法更多是借鉴了算法4的思想,因为个人觉得算法导论这部分对于树的讲解和代码处理并没有算法4的简洁和易于理解。不过标题还是取作算法导论之xxx是因为我博客整体的代码实现都是按照算法导论中安排的课程流程进行展开的。不多废话,上代码和注释!
package org.loda.structure;
/**
*
* @ClassName: BST
* @Description: 二叉树 binary search tree
* @author minjun
* @date 2015年5月16日 下午8:37:59
*
* @param <K>
* @param <V>
*/
public class BST<K extends Comparable<K>, V> {
/**
* 根节点
*/
private Node root;
private class Node {
K k;
V v;
Node left;
Node right;
public Node(K k,V v){
this.k=k;
this.v=v;
}
}
/**
*
* @Title: get
* @Description: 根据指定的key去查找该节点,并返回这个节点的value
* @param @param k
* @param @return 设定文件
* @return V 返回类型
* @throws
*/
public V get(K k) {
if (k == null)
throw new NullPointerException("查找的key不能为空");
Node node = get(k, root);
return node == null ? null : node.v;
}
/**
*
* @Title: get
* @Description: 将x作为根节点,查找该二叉树下面key为k的节点
* @param @param k
* @param @param x
* @param @return 设定文件
* @return Node 返回类型
* @throws
*/
private Node get(K k, Node x) {
//如果没有找到,那么直接返回空
if(x==null)
return null;
int c = k.compareTo(x.k);
if (c == 0) {
// 刚好找到该节点
return x;
} else if (c > 0) {
// 若要找的节点key值较大,说明该节点位于x的右边
return get(k, x.right);
} else {
// 若要找的节点key值较小,说明该节点位于x的左边
return get(k, x.left);
}
}
/**
*
* @Title: put
* @Description: 添加key为k,value为v的节点。如果key已经存在,那么更新该节点的值为v
* @param @param k
* @param @param v 设定文件
* @return void 返回类型
* @throws
*/
public void put(K k,V v){
if(k==null)
throw new NullPointerException("添加的key不能为空");
if(v==null)
delete(k);//如果key不为空而value为空,那么就删除key为k的节点
root=put(k, v,root);
}
/**
*
* @Title: put
* @Description: 将x作为根节点,往该二叉树下面添加key为k,value为v的节点
* @param @param k
* @param @param v
* @param @param x
* @param @return 设定文件
* @return Node 返回类型
* @throws
*/
private Node put(K k, V v, Node x) {
//如果不存在key为k的节点,那么就新增该节点
if(x==null)
return new Node(k,v);
int c=k.compareTo(x.k);
if(c==0){
//如果存在key为k的节点,那么就更新该节点
x.k=k;
x.v=v;
}else if(c>0){
//如果key值比x节点的key值更大,说明要添加的节点位于x右边
x.right=put(k, v, x.right);
}else{
//如果key值比x节点的key值更小,说明要添加的节点位于x左边
x.left=put(k, v, x.left);
}
return x;
}
/**
*
* @Title: delete
* @Description: 删除键为k的节点
* @param @param k 设定文件
* @return void 返回类型
* @throws
*/
public void delete(K k) {
if(k==null)
throw new NullPointerException("删除操作key不能为空");
root=delete(k,root);
}
/**
*
* @Title: delete
* @Description: 将x作为根节点,删除该二叉树下面key为k的节点
* @param @param k
* @param @param x
* @param @return 设定文件
* @return Node 返回类型
* @throws
*/
private Node delete(K k, Node x) {
if(x==null)
return null;
int c=k.compareTo(x.k);
if(c==0){
//如果找到该key所对应的节点,那么删除它
//当x右节点或者左节点为空时,则返回他另外一边的节点,用来"衔接"上删除后的空位
if(x.right==null)
return x.left;
if(x.left==null)
return x.right;
//当x拥有两个孩子节点的时候,会比较麻烦
//首先存储要被删除的节点,以便于之后使用
Node t=x;
//然后找到该节点右节点中最小的元素,填补上删除该节点后的空缺
x=min(x.right);
//为新的x节点设置左右孩子节点
//由于x是删除节点t的右孩子节点中的其中一个衔接上的,所以,该节点必然大于t的左节点,那么可以直接将t的左节点赋值给新x节点的左节点
x.left=t.left;
//由于t的右边节点中的最小的那个会被当做新的x节点填补上来,那么剩下的最小的那个就应该被当做x的右节点而存在了
x.right=deleteMin(x.right);
}else if(c>0){
//如果要删除的节点key值大于x的key值,说明该节点位于x右边
x.right=delete(k, x.right);
}else{
//如果要删除的节点key值小于x的key值,说明该节点位于x左边
x.left=delete(k, x.left);
}
return x;
}
/**
*
* @Title: deleteMin
* @Description: 以x作为根节点,删除该二叉树下key最小的节点
* @param @param x
* @param @return 设定文件
* @return Node 返回类型
* @throws
*/
private Node deleteMin(Node x) {
if(x==null)
throw new NullPointerException("要删除的节点不能为空");
if(x.left==null)
return x.right;
x.left=deleteMin(x.left);
return x;
}
/**
*
* @Title: min
* @Description: 查找以x作为根节点的二叉树下key最小的节点
* @param @param x
* @param @return 设定文件
* @return Node 返回类型
* @throws
*/
private Node min(Node x) {
if(x==null)
throw new NullPointerException("节点不能为空");
//如果左节点为空,那么表示它就是最小的节点
if(x.left==null)
return x;
return min(x.left);
}
/**
*
* @Title: printTree
* @Description: 按照自然顺序打印二叉树
* @param 设定文件
* @return void 返回类型
* @throws
*/
public void printTree(){
printTree(root);
}
/**
*
* @Title: printTree
* @Description: 以x为根节点,按照自然顺序打印该二叉树
* @param @param x 设定文件
* @return void 返回类型
* @throws
*/
private void printTree(Node x) {
if(x!=null){
printTree(x.left);
System.out.println(x.k+":"+x.v);
printTree(x.right);
}
}
public static void main(String[] args) {
BST<Integer, String> bst=new BST<Integer, String>();
// bst.put(3,"ccc");
// bst.put(2, "bbb");
// bst.put(4, "ddd");
// bst.put(7, "ggg");
// bst.put(1, "aaaa");
for(int i=0;i<10;i++){
bst.put((int)Math.round(Math.random()*100), "bbds");
}
// bst.delete(3);
// System.out.println(bst.get(3));
bst.printTree();
}
}