定义
一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
特点
树的结构通常不是一次生成的,而是在查找过程中,当树中不存在 关键字 等于给定值的 结点 时再进行插入。 新插入的结点一定是一个新添加的 叶子结点 ,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。 首先执行查找算法,找出被插结点的父亲结点。 判断被插结点是其父亲结点的左、右儿子。 将被插结点作为 叶子结点 插入
性能
每个结点的C(i)为该结点的层次数。最坏情况下,当先后插入的关键字有序时,构成的二叉排序树蜕变为单支树,树的深度为其平均查找长度(n+1)/2(和顺序查找相同),最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log 2 (n)成正比。
也就是说,最好情况下的算法时间复杂度为O(1),最坏情况下的算法时间复杂度为O(n)。
创建
首先创建一个arr数组,把这个数组的值一次添加在二叉树中
public void add(Node node){
if(node.getData() < this.data){
if(this.left == null){
this.setLeft(node);
}else {
this.left.add(node);
}
}else {
if(this.right == null){
this.setRight(node);
}else {
this.right.add(node);
}
}
}
BinarySortTree binarySortTree = new BinarySortTree();
//循环的添加结点到二叉排序树
for(int i = 0; i< arr.length; i++) {
binarySortTree.add(new Node(arr[i]));
}
遍历
二叉排序树也是和普通的二叉树遍历一致
public void infixOrder(){
if(this.left != null){
this.left.infixOrder();
}
System.out.println(this);
if(this.right != null){
this.right.infixOrder();
}
}
删除
在删除二叉排序树上某个结点之后,仍然保持二叉排序树的特性,即:二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字
删除结点有三种情况
1.被删除的结点是叶子
2.被删除的结点只有左子树或者只有右子树
3.被删除的结点既有左子树,也有右子树
第一种:被删除的结点是叶子
由于要删除的结点p即无左子树,又无右子树,
因此删除结点p之后不会破坏二叉排序树结构的完整性,
只要将其双亲结点f原来指向p的指针改为指向空即可
if(currentNode.left == null && currentNode.right == null){
Node parent = searchParent(data); // 找到父节点
if(parent.left != null && parent.left.data == data) { //根据值来判断自己是否属于左还是右子树,然后指向空
parent.left = null;
} else if (parent.right != null && parent.right.data == data) {
parent.right = null;
}
}
第二种:被删除的结点只有左子树或者只有右子树
要删除的结点p只有左子树PL或者右子树PR,
这时候只要将p的左子树PL或p的右子树PR
直接作为其双亲结点f 的相应左子树或右子树即可
if(currentNode.left != null) { // 只有左子节点
if(parent != null) {
if(parent.left.data == data) { // 1)根据值来判断自己是否属于左还是右子树, 然后父节点的左指向当前节点的左节点
parent.left = currentNode.left;
} else {
parent.right = currentNode.left; // 2)父节点的右指向当前节点的左节点
}
} else {
root = currentNode.left; // 父节点为空, 指向当前的左节点
}
} else {
if(parent != null) {
if(parent.left.data == data) { // 1)根据值来判断自己是否属于左还是右子树, 然后父节点的左指向当前节点的右节点
parent.left = currentNode.right;
} else {
parent.right = currentNode.right; // 2)父节点的右指向当前节点的左节点
}
} else {
root = currentNode.right; // 父节点为空 指向当前的右节点
}
}
第三种:被删除的结点既有左子树,也有右子树
(1)需求先去找到要删除的结点current
(2)找到current的父结点parent
(3) 从current的右子树找到最小的结点
(4)用一个临时变量,将最小结点的值保存temp
5)删除该最小结点
6) current.data = temp
Node current = search(data);
Node current = searchParent(current);
Node mixParent = search(data);
while(mixParent.left != null) {
mixParent = mixParent.left;
}
int temp = mixParent.data;
delNode(mixParent.data);
current.data = temp;