使二叉树成为二叉查找树的性质是,对于树中的每个节点 X ,它的左子树中所有项的值小于 X 中的值,而它右子树中所有项的值大于 X 中的值。
注意,这意味着该树所有的元素可以用某种一致的方式排序。
首先定义一个节点类:
private static class BinaryNode<T>{
T element;
BinaryNode<T> left;
BinaryNode<T> right;
public BinaryNode( T element ) {
this( element, null, null );
}
public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
this.element = element;
this.left = left;
this.right = right;
}
}
public boolean contains( T x ){
return contains( x, root );
}
private boolean contains( T x, BinaryNode<T> t ){
if( t == null )
return false;
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
return contains( x, t.left );
}
else if( compareResult > 0 ){
return contains( x, t.right );
}
else{
return true;
}
}
递归方法实现:
public T findMin(){
if( isEmpty() )
throw new UnderflowException();
return findMin( root ).element;
}
/**
* 递归的方法
* @param t
* @return
*
* Date :2012-7-6
* Author :GongQiang
*/
private BinaryNode<T> findMin( BinaryNode<T> t ){
if( t == null ){
return null;
}
else if( t.left == null ){
return t;
}
return findMin( t.left );
}
非递归方法实现:
public T findMax(){
if( isEmpty() )
throw new UnderflowException();
return findMax( root ).element;
}
/**
* 循环迭代
* @param t
* @return
*
* Date :2012-7-6
* Author :GongQiang
*/
private BinaryNode<T> findMax( BinaryNode<T> t ){
if( t!= null ){
while( t.right != null )
t = t.right;
}
return t;
}
insert 方法
为了将 X 插入到数 T 中,你可以像用 contains 那样沿着树查找。如果找到 X ,则什么也不用做(或做一些“更新”)。否则将 X 插入到遍历的路径上的最后一点上。
public void insert( T x ){
root = insert( x, root );
}
private BinaryNode<T> insert( T x, BinaryNode<T> t ){
if( t == null )
return new BinaryNode<T>( x, null, null );
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
t.left = insert( x, t.left );
}
else if( compareResult > 0 ){
t.right = insert( x, t.right );
}
else{
; // 重复,不做任何操作
}
return t;
}
如果节点是一片树叶,那么它可以被立即删除;
如果节点有一个儿子,则该节点可以在其父节点调整自己的链绕过该节点后被删除;
如果处理具有两个儿子的节点。一般的删除策略是用其右子树的最小的数据代替该节点的数据并递归地删除那个节点(现在它是空的)。因为右子树中的最小的节点不可能有左儿子,所以第二次 remove 要容易。
public void remove( T x ){
root = remove( x, root );
}
private BinaryNode<T> remove( T x, BinaryNode<T> t ){
if( t == null )
return t; // Item not found; do nothing
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
t.left = remove( x, t.left );
}
else if( compareResult > 0 ){
t.right = remove( x, t.right );
}
else if( t.left != null && t.right != null ){ // Two children
t.element = findMin( t.right ).element;
t.right = remove( t.element, t.right );
}
else{
t = ( t.left != null )? t.left : t.right;
}
return t;
}
如果删除的次数不多,通常使用的策略是懒惰删除:当一个元素要被删除时,它仍留在树中,而只是被标记为删除。这特别是在有重复项时很常用,因为此时记录出现频率数的域可以减 1 。如果树中的实际节点数和“被删除”的节点数相同,那么树的深度预计只是上升一个小的常数,因此,存在一个与懒惰删除相关的非常小的时间损耗。再有,如果被删除的项重新插入的,那么分配一个新单元的开销就避免了。
完整代码:
public class BinarySearchTree<T extends Comparable<? super T>> {
private static class BinaryNode<T>{
T element;
BinaryNode<T> left;
BinaryNode<T> right;
public BinaryNode( T element ) {
this( element, null, null );
}
public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
this.element = element;
this.left = left;
this.right = right;
}
}
private BinaryNode<T> root;
public BinarySearchTree() {
root = null;
}
public void makeEmpty(){
root = null;
}
public boolean isEmpty(){
return root == null;
}
public boolean contains( T x ){
return contains( x, root );
}
private boolean contains( T x, BinaryNode<T> t ){
if( t == null )
return false;
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
return contains( x, t.left );
}
else if( compareResult > 0 ){
return contains( x, t.right );
}
else{
return true;
}
}
public T findMin(){
if( isEmpty() )
throw new UnderflowException();
return findMin( root ).element;
}
/**
* 递归的方法
* @param t
* @return
*
* Date :2012-7-6
* Author :GongQiang
*/
private BinaryNode<T> findMin( BinaryNode<T> t ){
if( t == null ){
return null;
}
else if( t.left == null ){
return t;
}
return findMin( t.left );
}
public T findMax(){
if( isEmpty() )
throw new UnderflowException();
return findMax( root ).element;
}
/**
* 循环迭代
* @param t
* @return
*
* Date :2012-7-6
* Author :GongQiang
*/
private BinaryNode<T> findMax( BinaryNode<T> t ){
if( t!= null ){
while( t.right != null )
t = t.right;
}
return t;
}
public void insert( T x ){
root = insert( x, root );
}
private BinaryNode<T> insert( T x, BinaryNode<T> t ){
if( t == null )
return new BinaryNode<T>( x, null, null );
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
t.left = insert( x, t.left );
}
else if( compareResult > 0 ){
t.right = insert( x, t.right );
}
else{
; // 重复,不做任何操作
}
return t;
}
public void remove( T x ){
root = remove( x, root );
}
private BinaryNode<T> remove( T x, BinaryNode<T> t ){
if( t == null )
return t; // Item not found; do nothing
int compareResult = x.compareTo( t.element );
if( compareResult < 0 ){
t.left = remove( x, t.left );
}
else if( compareResult > 0 ){
t.right = remove( x, t.right );
}
else if( t.left != null && t.right != null ){ // Two children
t.element = findMin( t.right ).element;
t.right = remove( t.element, t.right );
}
else{
t = ( t.left != null )? t.left : t.right;
}
return t;
}
public void printTree(){
//前序输出
printTree( root );
}
private void printTree( BinaryNode<T> t ){
if( t != null ){
printTree( t.left );
System.out.println( t.element );
printTree( t.right );
}
}
}
class UnderflowException extends RuntimeException{
private static final long serialVersionUID = 1L;
}