本文基于BST结构主要实现查找,删除功能
此种数据结构较为简单,主要分析添加查找删除功能
后附完整代码
1.BST定义:
1).每个结点均有键值对,其中键值实现排序;
2).每个结点的都大于它的左结点,小于它的右结点。
2. 主要实现(递归)
结点内部类Node:
`private class Node
{
private Key key;
private Value value;
private Node left ,right;
private int N;
public Node(Key key,Value value,int N)
{
this.key = key;
this.value = value;
this.N = N;
}
}
`
1).添加put
思想:键值不能相同的原则,所以先递归查找是否存在这样的键值,若存在,则更新value值,否则添加相应的键值对到对应的位置。
实现:
private Node put(Node x,Key key,Value value)
{
if(x == null)
return new Node(key,value,1);
int cmp = key.compareTo(x.key);
if (cmp<0)
x.left = put(x.left,key,value);
else if (cmp>0)
x.right = put(x.right,key,value);
else
x.value = value;
x.N = size(x.left)+size(x.right)+1;
return x;
}
2).删除deleteMin,delete
1.删除最小值:
查找最小值:递归查找左子树,若左子树为null,则递归右子树,查找Node.left==null的结点,次结点即为树的最小值。
删除最小值:删除最小值后,最小结点的右子树,接到最小值父结点的左子树中。
private Node deleteMin(Node x)
{
if(x.left == null)
//此处返回需要删除的最小结点的右子树(这样才能保证后面结点不丢失).
return x.right;
//递归到最小结点时,返回了x.right,此处令最小结点的父结点的左子树等于返回的x.right.
//而需要删除的结点,被当成垃圾系统回收.
x.left = deleteMin(x.left);
//更新计数器.
x.N = size(x.left)+size(x.right)+1;
return x;
}
2.删除任意结点(传入键值):
思想:首先肯定先递归查找的删除的键值(假设x结点),删除结点x时,我们需要使用到deleteMin,找到以x为父结点的子树的,用于替换x位置的结点。
private Node delete(Node x,Key key)
{
if(x == null)
return null;
int cmp = key.compareTo(x.key);
if(cmp < 0)
x.left = delete(x.left,key);
else if(cmp > 0)
x.right = delete(x.right,key);
else
{
//此处x为需要删除的结点.判断x是否为单结点,若为单结点,返回x.left或者x.right即能删除x结点.
if(x.right == null)
return x.left;
if(x.left == null)
return x.right;
//若不为单结点.创建t结点,保存x的左右连接状态,再查找x右子树的最小结点(此结点即为新的取代x结点的结点).
Node tmp = x;
x = min(tmp.right);
x.right = deleteMin(tmp.right);
x.left = tmp.left;
}
x.N = size(x.left)+size(x.right)+1;
return x;
}
3.性能分析:
二分查找法(有序数组):
最坏:查找—lgN。插入—N
平均:查找—lgN。插入—N/2
二叉查找树:
最坏:查找—N。插入—N
平均:查找—1.39lgN。插入—1.39lgN
BST的性能与树的高度成正比。
3. 完整代码
package search;
/**
* @author : 罗正
* @date time:2016年9月7日 下午9:47:08
**/
public class BSTsearch <Key extends Comparable<Key> ,Value>{
private Node root;
/**
* 内部类:树结点——Node
* @param args
*/
private class Node
{
private Key key;
private Value value;
private Node left ,right;
private int N;
public Node(Key key,Value value,int N)
{
this.key = key;
this.value = value;
this.N = N;
}
}
public int size(){
return size(root);
}
private int size(Node x)
{
if (x == null)
return 0;
else
return x.N;
}
/**
* funtion:根据传入的key值,递归查找二叉树,无则返回null.
* @param key
* @return
*/
public Value get (Key key)
{
return get(root,key);
}
private Value get(Node x,Key key)
{
if(x == null)
return null;
int cmp = key.compareTo(x.key);
if (cmp<0)
return get(x.left,key);
else if (cmp>0)
return get(x.right,key);
else
return x.value;
}
/**
* 查找key值,找到则更新,没有则添加.
* @param key
* @param value
*/
public void put(Key key,Value value)
{
root = put(root,key,value);
}
/**
* 没有则插入root的子树当中
* @param x
* @param key
* @param value
* @return
*/
private Node put(Node x,Key key,Value value)
{
if(x == null)
return new Node(key,value,1);
int cmp = key.compareTo(x.key);
if (cmp<0)
x.left = put(x.left,key,value);
else if (cmp>0)
x.right = put(x.right,key,value);
else
x.value = value;
x.N = size(x.left)+size(x.right)+1;
return x;
}
public Key min()
{
return min(root).key;
}
private Node min(Node x)
{
if(x.left == null)
return x;
return min(x.left);
}
/**
* 返回小于等于key的最大键.
* @param key
* @return
*/
public Key floor(Key key)
{
Node x = floor(root,key);
if(x == null)
return null;
return x.key;
}
private Node floor(Node x,Key key)
{
if( x == null)
return x;
int cmp = key.compareTo(x.key);
if(cmp == 0)
return x;
if(cmp<0)
return floor(x.left,key);
Node t = floor(x.right,key);
if(t != null)
return t;
else
return x;
}
/**
* 根据传入的int k值,查找在树中的key值,并返回
* @param k
* @return
*/
public Key select(int k)
{
return select(root,k).key;
}
private Node select(Node x,int k)
{
if(x == null)
return null;
int num = size(x.left);
if(num > k)
return select(x.left,k);
else if(num < k)
return select(x.right,k-num-1);
else
return x;
}
/**
* 根据传入的key,查找在树中的rank.
* @param key
* @return
*/
public int rank(Key key)
{
return rank(root,key);
}
private int rank(Node x,Key key)
{
if( x == null)
return 0;
int cmp = key.compareTo(x.key);
if(cmp > 0)
//此处不要忘了加上1+size(x.left)
return 1+size(x.left)+rank(x.right,key);
if(cmp < 0)
return rank(x.left,key);
else
return size(x.left);
}
/**
* 以下为较难实现的BST删除操作.
* 实现步骤如下:
* 1.保存要删除的结点链接.(如删除A,保存t = B.left).
* 2.A指向X = min(A.left).<这个结点就是删A后,取代A位置的结点!>
* 3.X取代A的操作,以及X位置抽取后,树变动的操作
*
* deletemMin().
* delete().
*/
public void deleteMin()
{
root = deleteMin(root);
}
private Node deleteMin(Node x)
{
if(x.left == null)
return x.right;
x.left = deleteMin(x.left);
x.N = size(x.left)+size(x.right)+1;
return x;
}
/**
* 删除给定的键值对key.
* @param key
*/
public void delete(Key key)
{
root = delete(root,key);
}
/**
* 递归删除key,
* 返回Node值,便于实现递归而不丢失链接.
* @param x
* @param key
* @return
*/
private Node delete(Node x,Key key)
{
if(x == null)
return null;
int cmp = key.compareTo(x.key);
if(cmp < 0)
x.left = delete(x.left,key);
else if(cmp > 0)
x.right = delete(x.right,key);
else
{
//此处x为需要删除的结点.判断x是否为单结点,若为单结点,返回x.left或者x.right即能删除x结点.
if(x.right == null)
return x.left;
if(x.left == null)
return x.right;
//若不为单结点.创建t结点,保存x的左右连接状态,再查找x右子树的最小结点(此结点即为新的取代x结点的结点).
Node tmp = x;
x = min(tmp.right);
x.right = deleteMin(tmp.right);
x.left = tmp.left;
}
x.N = size(x.left)+size(x.right)+1;
return x;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BSTsearch bst = new BSTsearch<>();
bst.put("B", "b");
bst.put("A", "a");
bst.put("D", "d");
bst.put("W", "w");
bst.put("X", "x");
bst.put("Z", "z");
System.out.println(bst.select(0));
System.out.println("rank A:"+bst.rank("A"));
System.out.println("bst size :"+bst.size());
System.out.println("floor:"+bst.floor("Z"));
System.out.println("min :"+bst.min());
bst.deleteMin();
System.out.println("min (mid):"+bst.min());
bst.delete("B");
System.out.println("min :"+bst.min());
System.out.println("bst size:"+bst.size());
}
}
算法第四版—二叉查找树