先了解下二叉查找树的基本概念:
二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
它或者是一棵空树;或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
如下图就是一棵二叉树
下面重点解析下二叉查找树的删除操作
在二叉排序树删去一个结点,分三种情况讨论:
-
若当前结点为叶子结点,即left(左子树)和right(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
-
若当前结点只有左子树left或右子树right,此时只要令left或right直接成为其双亲结点的左子树(要删除的结点是左子树)或右子树(要删除的结点是右子树)即可,作此修改也不破坏二叉排序树的特性。如下图:
删除前:
删除后:
-
若当前结点的左子树和右子树均不空。在删去当前结点之后,为保持其它元素之间的相对位置不变,则需找到当前结点右子树中最小的结点,并用其数据替换当前结点的数据,然后递归的删除找到的最小的结点。如下图:
删除前:
删除后:
下面给出二叉查找树的二叉链表的实现代码
/**
* 二叉查找树的链式存储结构的实现
* @author lenovo
*
* @param <T>
*/
public class BinarySearchTree <T extends Comparable<? super T>>{
private static class BinaryNode<T> {
T element; //节点数据
BinaryNode<T> left; //左子节点
BinaryNode<T> right; //右子节点
BinaryNode(T theElement) {
this(theElement, null, null);
}
BinaryNode(T theElement, BinaryNode<T> lt, BinaryNode<T> rt) {
// TODO Auto-generated constructor stub
this.element = theElement;
this.left = lt;
this.right = rt;
}
}
private BinaryNode<T> root; //唯一的数据域,对根节点的引用
public BinarySearchTree() {
this.root = null;
}
public void makeEmpty() {
this.root = null;
}
public boolean isEmpty() {
return root == null;
}
public boolean contains(T x) {
return contains(x,root);
}
public BinaryNode<T> findMin() {
if (isEmpty()) {
System.out.println("Empty Tree!");
System.exit(-1);
}
return (BinaryNode<T>) findMin(root).element;
}
public BinaryNode<T> findMax() {
if (isEmpty()) {
System.out.println("Empty Tree!");
System.exit(-1);
}
return (BinaryNode<T>) findMax(root).element;
}
public void insert(T x) {
root = insert(x, root);
}
public void remove(T x) {
root = remove(x, root);
}
public void printTree() {
if (isEmpty()) {
System.out.println("Empty Tree!");
}
else {
printTree(root);
}
}
/**
* 在一棵子树中查找项X
* @param x
* @param t
* @return
*/
private boolean contains(T x, BinaryNode<T> t) {
if (t == null) {
return false;
}
int compResult = x.compareTo(t.element);
if (compResult < 0) {
return contains(x, t.left); //递归调用
}
else if(compResult > 0) {
return contains(x, t.right);
}
else {
return true; //匹配
}
}
/**
*
* @param t
* @return 返回树中包含最小元的引用
*/
private BinaryNode<T> findMin(BinaryNode<T> t) {
if (t == null) {
return null;
}
else if (t.left == null) {
return t;
}
return findMin(t.left); //使用递归逐层遍历左子树
}
/**
*
* @param t
* @return 返回树中包含最大元的引用
*/
private BinaryNode<T> findMax(BinaryNode<T> t) {
/*if (t == null ){
return null;
}
else if(t.right == null) {
return t;
}
return findMax(t.right);*/ //使用递归逐层遍历左子树
//非递归实现
if (t != null) {
while (t.right != null) {
t = t.right;
}
}
return t;
}
/**
* 将项X插入一棵子树
* @param x
* @param t
* @return
*/
private BinaryNode<T> insert(T x, BinaryNode<T> t) {
if (t == null) {
return null;
}
int compResult = x.compareTo(t.element);
if (compResult < 0) {
t.left = insert(x, t.left);
}
else if (compResult > 0) {
t.right = insert(x, t.right);
}
else {
; //如果重复,什么也不做
}
return t;
}
private BinaryNode<T> remove(T x, BinaryNode<T> t) {
if (t == null) {
return null;
}
int compResult = x.compareTo(t.element);
if (compResult < 0) {
t.left = remove(x, t.left);
}
else if (compResult > 0) {
t.right = remove(x, t.right);
}
else if (t.left != null && t.right != null){ //两个孩子的情况
t.element = findMin(t.right).element; //查找和删除右子树中最小的节点
t.right = remove(t.element, t.right);
}
else {
t = (t.left != null) ? t.left : t.right;
}
return t;
}
private void printTree(BinaryNode<T> t) {
if (t != null) {
printTree(t.left);
System.out.println(t.element);
printTree(t.right);
}
}
若有任何问题欢迎提出,互相交流学习(●'◡'●)