一、算法
二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树。 它或者是一棵空树;或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值; (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值; (3)左、右子树也分别为二叉排序树;
不得不说二叉查找树的插入和删除非常麻烦,可谓是费了九牛二虎之力才把代码写完。支持Insert,Delete,Search,Min,Max,Successor,Predecessor等操作。BST在数据结构中占有很重要的地位,一些高级树结构都是其的变种,例如AVL树、红黑树等,因此理解BST对于后续树结构的学习有很好的作用。
二、java代码
<span style="font-size:14px;">package com.tangbo;
public class BinarySearchTree<T extends Comparable<T>> {
Node<T> root;
public BinarySearchTree() {
super();
}
/*
* 插入一个元素T t
*/
public void insert(T t) {
Node<T> node = new Node<T>(t);
if(node.getKey()==null)
{
throw new IllegalArgumentException("插入的元素不能为空!");
}
if(root == null)
{
root = node;
}else
{
Node<T> temp = root;
while(true)
{
if(node.getKey().compareTo(temp.getKey())>0)
{
if(temp.getRightNode()==null)
{
node.setParentNode(temp);
temp.setRightNode(node);
break;
}else
{
temp = temp.getRightNode();
}
}else
{
if(temp.getLeftNode()==null)
{
node.setParentNode(temp);
temp.setLeftNode(node);
break;
}else
{
temp = temp.getLeftNode();
}
}
}
}
}
//计算该节点的有几个孩子节点
private int childCount(Node<T> node) {
if (node == null) {
throw new IllegalArgumentException("节点不能为空");
}
int count = 0;
if (node.getLeftNode() != null) {
count++;
}
if (node.getRightNode() != null) {
count++;
}
return count;
}
//删除一个节点
public void delete(Node<T> node) {
if (node == null) {
throw new IllegalArgumentException("删除节点不能为空!");
}
int childCount = childCount(node);
Node<T> parentNode = node.getParentNode();
if (childCount == 0) {
if (parentNode == null) {
root = null;
} else {
if (node == parentNode.getLeftNode()) {
parentNode.setLeftNode(null);
} else {
parentNode.setRightNode(null);
}
}
} else if (childCount == 1) {
if (parentNode == null) {
if (node.getLeftNode() != null) {
root = node.getLeftNode();
node.getLeftNode().setParentNode(null);
} else {
root = node.getRightNode();
node.getRightNode().setParentNode(null);
}
} else {
if (node == parentNode.getLeftNode()) {
if (node.getLeftNode() != null) {
parentNode.setLeftNode(node.getLeftNode());
node.getLeftNode().setParentNode(parentNode);
} else {
parentNode.setLeftNode(node.getRightNode());
node.getRightNode().setParentNode(parentNode);
}
} else {
if (node.getLeftNode() != null) {
parentNode.setRightNode(node.getLeftNode());
node.getLeftNode().setParentNode(parentNode);
} else {
parentNode.setRightNode(node.getRightNode());
node.getRightNode().setParentNode(parentNode);
}
}
}
} else {
//后继没有左孩子
Node<T> successor = min(node);
if (successor != node.getRightNode()) {
transplant(successor, successor.getRightNode());
successor.setRightNode(node.getRightNode());
node.getRightNode().setParentNode(successor);
}
transplant(node, successor);
successor.setLeftNode(node.getLeftNode());
node.getLeftNode().setParentNode(successor);
}
}
private void transplant(Node<T> u, Node<T> v) {
if (u == null) {
throw new IllegalArgumentException("节点不能为空");
}
if (u.getParentNode() == null) {
root = v;
} else if (u == u.getParentNode().getLeftNode()) {
u.getParentNode().setLeftNode(v);
} else {
u.getParentNode().setRightNode(v);
}
if (v != null) {
v.setParentNode(u.getParentNode());
}
}
//查找
public Node<T> search(T key) {
Node<T> temp = root;
int result;
while(root!=null)
{
result = key.compareTo(temp.getKey());
switch (result) {
case 0:
return temp;
case 1:
temp = temp.getRightNode();
break;
case -1:
temp = temp.getLeftNode();
break;
}
}
return null;
}
//求节点rootNode下的最小节点
public Node<T> min(Node<T> rootNode) {
if(rootNode == null)
{
throw new IllegalArgumentException("参考节点不能为空!");
}else
{
while(rootNode.getLeftNode()!=null)
{
rootNode = rootNode.getLeftNode();
}
}
return rootNode;
}
//返回rootNode下最大的节点
public Node<T> max(Node<T> rootNode) {
if(rootNode == null)
{
throw new IllegalArgumentException("参考节点不能为空!");
}else
{
while(rootNode.getRightNode()!=null)
{
rootNode = rootNode.getRightNode();
}
}
return rootNode;
}
//返回一个节点的后继
public Node<T> successor(Node<T> rootNode) {
if(rootNode==null)
{
throw new IllegalArgumentException("参考节点不能为空!");
}
if(rootNode.getRightNode()!=null)
{
return min(rootNode.getRightNode());
}
Node<T> processNode = rootNode;
Node<T> parent = processNode.getParentNode(); //向上迭代
while (parent != null && processNode == parent.getRightNode()) {
processNode = parent;
parent = processNode.getParentNode();
}
return parent;
}
//返回一个节点的前驱
public Node<T> predecessor(Node<T> rootNode) {
if(rootNode==null)
{
throw new IllegalArgumentException("参考节点不能为空!");
}
if(rootNode.getLeftNode()!=null)//有左孩子的情况
{
return max(rootNode.getLeftNode());
}
Node<T> processNode = rootNode;
Node<T> parent = processNode.getParentNode();//向上迭代
while (parent != null && processNode == parent.getLeftNode()) {
processNode = parent;
parent = processNode.getParentNode();
}
return parent;
}
//根据数组t构建二叉树
public Node<T> buidBinarySearchTree(T[] t)
{
for(int i=0;i<t.length;i++)
{
insert(t[i]);
}
return root;
}
}
</span>
Node类:
<span style="font-size:14px;">package com.tangbo;
public class Node<T extends Comparable<T>> {
private Node<T> leftNode;
private T key;
private Node<T> rightNode;
private Node<T> parentNode;
public Node() {
super();
}
public Node(T t) {
key = t;
leftNode=null;
rightNode = null;
parentNode = null;
}
public Node<T> getLeftNode() {
return leftNode;
}
public void setLeftNode(Node<T> leftNode) {
this.leftNode = leftNode;
}
public Node<T> getRightNode() {
return rightNode;
}
public void setRightNode(Node<T> rightNode) {
this.rightNode = rightNode;
}
public Node<T> getParentNode() {
return parentNode;
}
public void setParentNode(Node<T> parentNode) {
this.parentNode = parentNode;
}
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
@Override
public String toString() {
return key+"";
}
}
</span>
如果大家认真的看代码,你会发现一个问题二叉搜索树对根节点有一个要求,最好根节点在选择的时候就能够处于数组的中间,因为如果根节点处于数组的两边(如果数组排序),就会导致这颗二叉树不平衡,就是总有一边的树枝太长,左右两边不太对等,更差的情况,如果这个数组T[] t已经被排序的话,那么这个二叉树就完全是一个链表,查找的速度是最差的,和平时的数组查找时间一样。那我们想一想,有没有什么方法,能够保持数时平衡的,就是左右子数的高度差不多呢?答案肯定有,就是“旋转”,具体有AVL树,在后续的文章中,我会把AVL树写出来!