二叉排序树

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) {}

3 完整代码

点击跳转到Github

posted @ 2020-06-03 16:41  、、、路遥  阅读(292)  评论(0编辑  收藏  举报