Binary Search Tree

Binary Search Tree

目录


概述

二叉搜索树的操作,包括插入和删除等。

二叉搜索树,又叫二叉查找树。若想使得二叉树成为二叉查找树,则对于树中的每个节点X

  • 它的左子树中所有关键字值小于X的关键字值
  • 它的右子树中所有关键字值大于X的关键字值

下图就是一个BST

这里写图片描述

可以看到,BST中的元素按照一定的规律排列。由于树本身就是递归定义的,因此通常对树的操作都是用递归来做,当然也可以利用循环实现。


因为BST的性质,查找操作还是比较简单的,假设树根为T,查找元素值为X:

  • 如果T是NULL,那么直接返回NULL,否则
  • 如果T的关键字是X,那么返回T,否则
  • 对T的左子树或者右子树进行一次递归调用。

时间复杂度: O(logN)
代码如下:

public static BinarySearchTree find(Integer ele, BinarySearchTree root) {       
        if(root == null) return null;
        if(ele < root.element) return find(ele, root.lchild);
        if(ele > root.element) return find(ele, root.rchild);       
        return root;
    }

Insert

插入也是很简单的

  • 比树根关键字值小就往左子树插入,否则
  • 比树根关键字值大就往右子树插入,否则
  • 那肯定就是相等啦,啥也不干(树中元素关键字不可以重复)
public static BinarySearchTree insert(Integer ele, BinarySearchTree root) {     
        if(root == null) {
            root = new BinarySearchTree();
            root.element = ele;
            root.lchild = root.rchild = null;           
        }
        else if(ele < root.element) root.lchild = insert(ele, root.lchild);
        else if(ele > root.element) root.rchild = insert(ele, root.rchild);
        //if(ele == root.element) do nothing        
        return root;
    }

// output
preOrder: 
6 2 1 5 3 4 8 
inOrder: 
1 2 3 4 5 6 8 
postOrder: 
1 4 3 5 2 8 6 

Delete

BST最麻烦的就是删除了,因为删除一个元素可能会破坏BST的特性,所以一般情况下都需要重新调整。
这里主要分三种情况:

  • 删除的节点x是叶子节点,那么可以立刻删除,否则
  • 删除的节点x只有一个孩子,则x的双亲节点指针直接指向x的孩子即可,否则
  • 删除的节点x有两个孩子,那么

这里写图片描述

主要说明一下有两个孩子的情况,如上图所示,想要删除节点2,那么

  • 首先找到节点2的右子树中元素最小的节点
  • 得到节点3
  • 把节点3的关键字值赋给节点2
  • 删除节点3,也就是把节点4赋给节点3
    /*
     * 删除树中元素关键字值最小的节点,返回删除后的树
     */
    public static BinarySearchTree deleteMin(BinarySearchTree root) {       
        if(root.lchild == null) return root.rchild;
        root.lchild = deleteMin(root.lchild);
        return root;
    }

    public static BinarySearchTree delete(Integer ele, BinarySearchTree root) {
        BinarySearchTree tmpBst = null; 

        if(root == null) return null;
        if(ele < root.element){ 
            root.lchild = delete(ele, root.lchild);
        } else if(ele > root.element) { 
            root.rchild = delete(ele, root.rchild);
        } else { // 找到了节点了
            if(root.lchild != null && root.rchild != null) { // 待删除节点有两个孩子              
                tmpBst = findMin(root.rchild); // 找到右子树中最小的元素
                root.element = tmpBst.element; // 替换
                root.rchild = deleteMin(root.rchild);  // 更新右子树为删除最小元素后的树                       
            } else { // 没有或者只有一个孩子
                tmpBst = root;
                if(root.lchild == null) root = root.rchild; 
                else if(root.rchild == null) root = root.lchild;
                tmpBst = null; // for gc
            }
        }

        return root;
    }

// delete 2 output
preOrder: 
6 3 1 5 4 8 
inOrder: 
1 3 4 5 6 8 
postOrder: 
1 4 5 3 8 6 

Summary

BST的插入和删除的平均时间在O(logN),这只是平均时间。如果是一串预先排好序的数据插入BST,那么它会退化成一根链表,实现的代价巨大,所以才有平衡树的出现,保证任何节点的深度不会过深。前面已经讨论过AVL,还有更复杂的红黑树,有兴趣的可以研究下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值