二叉查找树(Binary Search Tree)

本帖部分文字和图片来自于
https://zh.wikipedia.org/wiki/%E4%BA%8C%E5%85%83%E6%90%9C%E5%B0%8B%E6%A8%B9
http://www.cnblogs.com/huangxincheng/archive/2012/07/21/2602375.html

但所有代码均为原创

二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点。

这里写图片描述

二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低,为O(log n)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。

如何添加元素到二叉查询树中呢?

  • 若b是空树,则将s所指结点作为根节点插入,否则:
  • 若s->data等于b的根节点的数据域之值,则返回,否则:
  • 若s->data小于b的根节点的数据域之值,则把s所指节点插入到左子树中,否则:
  • 把s所指节点插入到右子树中。(新插入节点总是叶子节点)

这里写图片描述

首先定义二叉查找树类

public class BinarySearchTreeNode {
    public int value = 0;
    public BinarySearchTreeNode parent = null;
    public BinarySearchTreeNode left = null;
    public BinarySearchTreeNode right = null;
    public BinarySearchTreeNode(int value){
        this.value = value;
    }
}

然后定义add方法

public BinarySearchTreeNode add(int value, BinarySearchTreeNode node){
    if(node == null) {
        node = new BinarySearchTreeNode(value);
    }else {
        if (value< node.value) {
            node.left = add(value, node.left);
        } else {
            node.right = add(value, node.right);
        }
    }

打印整个二叉查找树:

public void printBST(BinarySearchTreeNode node){
    System.out.print("node = " + node.value);
    System.out.print(", node.parent = " + (node.parent==null?"null":node.parent.value));
    System.out.print(", left=" + (node.left==null?"null":node.left.value));
    System.out.print(", right=" + (node.right==null?"null":node.right.value));
    System.out.println("");
    if(node.left != null){
        printBST(node.left);
    }
    if(node.right != null){
        printBST(node.right);
    }
}

最后我们运行下面的代码进行测试:

int[] values = {20,15,25,10,18,30,12};
BinarySearchTreeNode root = null;
for(int i=0; i<values.length; i++) {
    root = add(values[i], root);
}
printBST(root);

以下是输出内容:

node = 20, node.parent = null, left=15, right=25
node = 15, node.parent = 20, left=10, right=18
node = 10, node.parent = 15, left=null, right=12
node = 12, node.parent = 10, left=null, right=null
node = 18, node.parent = 15, left=null, right=null
node = 25, node.parent = 20, left=null, right=30
node = 30, node.parent = 25, left=null, right=null

生成二叉查找树的问题解决了,那么如何查找呢
- 若b是空树,则搜索失败,否则:
- 若x等于b的根节点的数据域之值,则查找成功;否则:
- 若x小于b的根节点的数据域之值,则搜索左子树;否则:
- 查找右子树。

public BinarySearchTreeNode search(BinarySearchTreeNode node, int value){
    if(node != null) {
        if(value == node.value){
            return node;
        }else if (value < node.value) {
            return search(node.left, value);
        } else {
            return search(node.right, value);
        }
    }else{
        return null;
    }
}

>

System.out.println(“search 18 = ” + (search(root, 18)==null?”failure”:”success”));
System.out.println(“search 22 = ” + (search(root, 22)==null?”failure”:”success”));
输出结果:
search 18 = success
search 22 = failure

删除是最复杂的,主要考虑两种情况

单孩子的情况
这个比较简单,如果删除的节点有左孩子那就把左孩子顶上去,如果有右孩子就把右孩子顶上去,结束。
这里写图片描述

左右都有孩子的情况
首先可以这么想象,如果我们要删除一个数组的元素,那么我们在删除后会将其后面的一个元素顶到被删除的位置,如图
这里写图片描述

那么二叉树操作同样也是一样,我们根据”中序遍历“找到要删除结点的后一个结点,然后顶上去就行了,原理跟”数组”一样一样的。

这里写图片描述

代码如下:

public BinarySearchTreeNode delete(BinarySearchTreeNode node){
    if(node != null){
        if (node.left == null && node.right == null) {
            if(node.parent == null){
                node = null;
                return node;
            } else if (node.parent.left != null && node.parent.left.value == node.value) {
                node.parent.left = null;
            } else if (node.parent.right != null && node.parent.right.value == node.value) {
                node.parent.right = null;
            }
            return node.parent;
        } else if (node.left != null && node.right != null) {
            node.value = node.right.value;
            node = delete(node.right);
        } else {
            BinarySearchTreeNode parent = node.parent;
            BinarySearchTreeNode n = node.left == null ? node.right : node.left;
            n.parent = parent;
            if (node.parent.left != null && node.parent.left.value == node.value) {
                node.parent.left = n;
            } else if (node.parent.right != null && node.parent.right.value == node.value) {
                node.parent.right = n;
            }
            node = n;
        }
    }
    return node;
}

以下是测试代码:

System.out.println("it will delete 15");
BinarySearchTreeNode deleteNode15 = search(root, 15);
if(deleteNode15 != null && deleteNode15.parent != null) {
    System.out.println("delete 15 = " + (delete(deleteNode15) == null ? "failure" : "success"));
}else{
    deleteNode15 = null;
    System.out.println("There is no any node.");
}
printBST(root);

it will delete 15
delete 15 = success
node = 20, node.parent = null, left=18, right=25
node = 18, node.parent = 20, left=10, right=null
node = 10, node.parent = 18, left=null, right=12
node = 12, node.parent = 10, left=null, right=null
node = 25, node.parent = 20, left=null, right=30
node = 30, node.parent = 25, left=null, right=null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值