二叉排序树
1 描述
在二叉树的基础上衍生出的数据结构,对任意结点左右孩子节点之间都有顺序,如:左孩子<当前节点<右孩子节点。因此,提高了有序数据的搜索速率,类似于二分搜索法。
关于二叉树的在之前的章节中有描述。具体参考:二叉树的描述与实现
2 算法实现
2.1 接口设计
public interface BSTree<E> {
//添加元素
void add(E element);
//删除元素
void remove(E element);
//是否包含当前元素
boolean contains(E element);
}
2.2 类设计
public class BSTreeImpl<E> extends BinaryTree<E> implements BSTree<E>{
private Comparator<E> comparator;
public BSTreeImpl(Comparator<E> comparator){
super();
this.comparator = comparator;
}
public BSTreeImpl(){
this(null);
}
//比较两个元素的大小
@SuppressWarnings({ "unchecked" })
private int compare(E e1,E e2){
if(comparator != null){
return comparator.compare(e1, e2);
}else{
//强转使得在没有使用comparator比较器时E必须实现这个接口,又可使得在使用comparator比较器时不实现这个接口
return ((Comparable<E>)e1).compareTo(e2);
}
}
private void elementIsNullCheck(E element){
if(element == null){
throw new IllegalArgumentException("element must not be null");
}
}
}
2.3 接口实现
- 是否包含某元素
@Override
public boolean contains(E element) {
elementIsNullCheck(element);
return node(element) != null;
}
//根据传入的element获取对应的node
private Node<E> node(E element){
Node<E> node = root;
while(node != null){
int cmp = compare(element, node.element);
if(cmp == 0){
return node;
}else if(cmp > 0){
node = node.right;
}else if(cmp < 0){
node = node.left;
}
}
return null;
}
- 获取前驱结点
protected Node<E> predesessor(Node<E> node){
if(node == null){
return null;
}
//前驱结点在左子树
Node<E> p = node.left;
if(p != null){
while(p.right != null){
p = p.right;
}
return p;
}
//前驱结点在祖父结点
while(node.parent != null && node.parent.left == node){
node = node.parent;
}
//当前结点为父节点的右结点,或者父节点为空,均返回父节点
return node.parent;
}
- 获取后继结点
protected Node<E> successor(Node<E> node){
if(node == null){
return null;
}
//前驱结点在右子树
Node<E> p = node.right;
if(p != null){
while(p.left != null){
p = p.left;
}
return p;
}
//后继结点在祖父结点
while(node.parent != null && node == node.parent.right){
node = node.parent;
}
//能来到这里,当前结点为父节点的左结点,或者父节点为空,两者都可返回父节点
return node.parent;
}
- 添加一个元素
@Override
public void add(E element) {
elementIsNullCheck(element);
super.size ++;
if(root == null){
root = createNode(element, null);
root.parent = null;
afterAdd(root);
return;
}
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
while(node != null){
parent = node;
cmp = compare(element, node.element);
if(cmp < 0){
node = node.left;
}else if(cmp > 0){
node = node.right;
}else{
node.element = element; //由于compare只比较了某些属性,但其他属性可能不同,这里使用覆盖
return;
}
}
Node<E> newNode = createNode(element, parent);
if(cmp > 0){
parent.right = newNode;
}else{
parent.left = newNode;
}
afterAdd(newNode); //增加可扩展性,为后续AVL树和红黑树准备
}
protected void afterAdd(Node<E> node){}
- 删除一个元素
@Override
public void remove(E element) {
elementIsNullCheck(element);
remove(node(element));
}
private void remove(Node<E> node){
if(node == null) return;
size --;
//删除度为2的结点
if(node.hasTwoChildren()){
Node<E> s = successor(node);
node.element = s.element;
//remove(s); return;
node = s;
}
//删除度为1或者0的结点
Node<E> replacement = node.left != null?node.left : node.right;
if(replacement != null){ //度为1
replacement.parent = node.parent;
if(node.isLeftChild()){
node.parent.left = replacement;
}else if(node.isRightChild()){
node.parent.right = replacement;
}else if(node == root){
root = replacement;
root.parent = null;
}
}else{ //度为0
if(node.parent == null){ //根结点
root = null;
}else{
if(node.isLeftChild()){
node.parent.left = null;
}else{
node.parent.right = null;
}
}
}
afterRemove(node,replacement); //增加可扩展性,为后续AVL树,红黑树准备
}
protected void afterRemove(Node<E> node,Node<E> replacement) {}