B树是为磁盘或其他直接存取辅助存储设置而设计的一种平衡查找树。其能够有效降低磁盘I/O操作次数。许多数据库系统使用B树或B树的变形来储存信息。清明节这几天闲来无事,参考《算法导论》第二版第十八章的思想使用java语言实现了一颗简单的B树,在此跟大家分享下,就当是抛砖引玉,欢迎大家跟我讨论。
package com.discover;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 一颗B树的简单实现。
* <p/>
* 其实现原理参考《算法导论》第二版第十八章。
* <p/>
* 如果大家想读懂这些源代码,不妨先看看上述章节。
* <p/>
* TODO B树如何存储在文件系统中,大家不妨想想
*
* @author WangPing 欢迎转载,转载请标明原文地址
*
* @param <K> - 键类型
* @param <V> - 值类型
*/
public class BTree<K, V>
{
private static Log logger = LogFactory.getLog(BTree.class);
/**
* B树节点中的键值对。
* <p/>
* B树的节点中存储的是键值对。
* 通过键访问值。
*
* @param <K> - 键类型
* @param <V> - 值类型
*/
private static class Entry<K, V>
{
private K key;
private V value;
public Entry(K k, V v)
{
this.key = k;
this.value = v;
}
public K getKey()
{
return key;
}
public V getValue()
{
return value;
}
public void setValue(V value)
{
this.value = value;
}
@Override
public String toString()
{
return key + ":" + value;
}
}
/**
* 在B树节点中搜索给定键值的返回结果。
* <p/>
* 该结果有两部分组成。第一部分表示此次查找是否成功,
* 如果查找成功,第二部分表示给定键值在B树节点中的位置,
* 如果查找失败,第二部分表示给定键值应该插入的位置。
*/
private static class SearchResult<V>
{
private boolean exist;
private int index;
private V value;
public SearchResult(boolean exist, int index)
{
this.exist = exist;
this.index = index;
}
public SearchResult(boolean exist, int index, V value)
{
this(exist, index);
this.value = value;
}
public boolean isExist()
{
return exist;
}
public int getIndex()
{
return index;
}
public V getValue()
{
return value;
}
}
/**
* B树中的节点。
*
* TODO 需要考虑并发情况下的存取。
*/
private static class BTreeNode<K, V>
{
/** 节点的项,按键非降序存放 */
private List<Entry<K,V>> entrys;
/** 内节点的子节点 */
private List<BTreeNode<K, V>> children;
/** 是否为叶子节点 */
private boolean leaf;
/** 键的比较函数对象 */
private Comparator<K> kComparator;
private BTreeNode()
{
entrys = new ArrayList<Entry<K, V>>();
children = new ArrayList<BTreeNode<K, V>>();
leaf = false;
}
public BTreeNode(Comparator<K> kComparator)
{
this();
this.kComparator = kComparator;
}
public boolean isLeaf()
{
return leaf;
}
public void setLeaf(boolean leaf)
{
this.leaf = leaf;
}
/**
* 返回项的个数。如果是非叶子节点,根据B树的定义,
* 该节点的子节点个数为({@link #size()} + 1)。
*
* @return 关键字的个数
*/
public int size()
{
return entrys.size();
}
@SuppressWarnings("unchecked")
int compare(K key1, K key2)
{
return kComparator == null ? ((Comparable<K>)key1).compareTo(key2) : kComparator.compare(key1, key2);
}
/**
* 在节点中查找给定的键。
* 如果节点中存在给定的键,则返回一个<code>SearchResult</code>,
* 标识此次查找成功,给定的键在节点中的索引和给定的键关联的值;
* 如果不存在,则返回<code>SearchResult</code>,
* 标识此次查找失败,给定的键应该插入的位置,该键的关联值为null。
* <p/>
* 如果查找失败,返回结果中的索引域为[0, {@link #size()}];
* 如果查找成功,返回结果中的索引域为[0, {@link #size()} - 1]
* <p/>
* 这是一个二分查找算法,可以保证时间复杂度为O(log(t))。
*
* @param key - 给定的键值
* @return - 查找结果
*/
public SearchResult<V> searchKey(K key)
{
int low = 0;
int high = entrys.size() - 1;
int mid = 0;
while(low <= high)
{
mid = (low + high) / 2; // 先这么写吧,BTree实现中,l+h不可能溢出
Entry<K, V> entry = entrys.get(mid);
if(compare(entry.getKey(), key) == 0) // entrys.get(mid).getKey() == key
break;
else if(compare(entry.getKey(), key) > 0) // entrys.get(mid).getKey() > key
high = mid - 1;
else // entry.get(mid).getKey() < key
low = mid + 1;
}
boolean result = false;
int index = 0;
V value = null;
if(low &l