二叉搜索树的概念
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
简单的来说 **
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
原理
二叉搜索树(BST)又称二叉查找树或二叉排序树。一棵二叉搜索树是以二叉树来组织的,可以使用一个链表数据结构来表示,其中每一个结点就是一个对象。一般地,除了key和卫星数据之外,每个结点还包含属性lchild、rchild和parent,分别指向结点的左孩子、右孩子和双亲(父结点)。如果某个孩子结点或父结点不存在,则相应属性的值为空(NIL)。根结点是树中唯一父指针为NIL的结点,而叶子结点的孩子结点指针也为NIL。
结构
二叉搜索树是能够高效地进行如下操作的数据结构。
1.插入一个数值
2.查询是否包含某个数值
3.删除某个数值
性质
设x是二叉搜索树中的一个结点。如果y是x左子树中的一个结点,那么y.key≤x.key。如果y是x右子树中的一个结点,那么y.key≥x.key。
在二叉搜索树中:
1.若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。
2. 若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。
3.任意结点的左、右子树也分别为二叉搜索树。
时间复杂度
不论哪一种操作,所花的时间都和树的高度成正比。因此,如果共有n个元素,那么平均每次操作需要O(logn)的时间。
二叉搜索树的操作
查找
插入
- 如果树为空树,即根 == null,直接插入
- 如果树不是空树,按照查找逻辑确定插入位置,插入新结点
删除(难点)
设待删除结点为 cur, 待删除结点的双亲结点为 parent
- cur.left == null
1.cur 是 root,则 root = cur.right
2.cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
3.cur 不是 root,cur 是 parent.right,则 parent.right = cur.right - cur.right == null
1.cur 是 root,则 root = cur.left
2.cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
3.cur 不是 root,cur 是 parent.right,则 parent.right = cur.left - cur.left != null && cur.right != null
1.需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题。
性能分析
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:㏒₂N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2
算法实现
class BinarySearchTree {
static class BSNode {
public int val;
public BSNode left;
public BSNode right;
public BSNode(int val) {
this.val = val;
}
}
public BSNode root = null;
public BSNode search(int val) {
if(root == null) return null;
BSNode cur = root;
while (cur != null) {
if(cur.val == val) {
return cur;
}else if(cur.val < val) {
cur = cur.right;
}else {
cur = cur.left;
}
}
return null;
}
public boolean insert(int val) {
BSNode bsNode = new BSNode(val);
if(root == null) {
root = bsNode;
return true;
}
BSNode cur = root;
BSNode parent = null;
while (cur != null) {
if(cur.val == val) {
return false;
}else if(cur.val < val) {
parent = cur;
cur = cur.right;
}else {
parent = cur;
cur = cur.left;
}
}
//
if(parent.val < val) {
parent.right = bsNode;
}else {
parent.left = bsNode;
}
return true;
}
public void remove(int val) {
}
}
public boolean remove(int key) {
Node cur = root;
Node parent = null;
while (cur != null) {
if (key == cur.key) {
break;
} else if (key < cur.key) {
parent = cur;
cur = cur.left;
}else {
parent = cur;
cur = cur.right;
}
}
// 该元素不在二叉搜索树中
if(null == cur){
return false;
}
return true;
}
}
public class TestDemo {
public static void preOrder(BinarySearchTree.BSNode root) {
if(root == null) {
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
public static void inOrder(BinarySearchTree.BSNode root) {
if(root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
public static void main(String[] args) {
BinarySearchTree binarySearchTree = new BinarySearchTree();
binarySearchTree.insert(4);
binarySearchTree.insert(3);
binarySearchTree.insert(1);
binarySearchTree.insert(15);
binarySearchTree.insert(11);
preOrder(binarySearchTree.root);
System.out.println();
inOrder(binarySearchTree.root);
System.out.println();
try {
BinarySearchTree.BSNode ret = binarySearchTree.search(14);
System.out.println(ret.val);
}catch (NullPointerException e) {
System.out.println("没有找到当前的节点............");
e.printStackTrace();
}
}
}