二叉搜索树

本文详细介绍了二叉查找树的概念、性质及基本操作,包括插入、删除和查找,并提供了具体的实现代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念:二叉查找树(Binary Search Tree) (又:二叉搜索树,二叉排序树)
它或者是一棵空树,或者是具有下列性质的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树。
这里写图片描述
当我们对二叉搜索树进行中序遍历时,可以得到一个关键字的有序序列。

插入:
在向二叉搜索树中插入节点时
首先需要判断树是否存在。
如若是空树,则直接插入。
如果存在,则对插入的位置进行查找,在这里我们不允许相同的键值存在。
找到插入位置后,还应判断是在根节点的左子树还是右子树。

节点类型:

template<class K>
struct BinarySearchTreeNode     // 二叉搜索树的节点
{
    BinarySearchTreeNode<K> *_left;
    BinarySearchTreeNode<K> *_right;
    K _key;

    BinarySearchTreeNode(const K& key)
        :_key(key)
        , _left(NULL)
        , _right(NULL)
    {}
};

实现

template<class K>
class BinarySearchTree
{
public:
    typedef BinarySearchTreeNode<K> Node;
    BinarySearchTree()
        :_root(NULL)
    {}
    );
    bool Insert(const K& key) { //插入
        // 1. 空树
        // Node*cur 当前节点 Node*parent 上一次寻找后的节点
        // 2.不是空树,则找到一个空的位置
        // 如果 key大于cur->_key 则寻找右树,否则寻找左树
        // 如果此值已经存在,则返回一个false  因为不支持数据冗余
        // 找到最后一层根节点后插入
        if (_root == NULL){
            _root = new Node(key);
            return true;
        }
        Node *parent = NULL;
        Node *cur = _root;
        while (cur){
            if (cur->_key < key) {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                parent = cur;
                cur = cur->_left;
            }
            else   //数据相同,冗余
                return false;
        }
        if (key < parent->_key)
            parent->_left = new Node(key);
        else
            parent->_right = new Node(key);
        return true;
    }

删除:
在对搜索二叉树进行删除的时候,我们需要考虑以下情况:
1. 二叉树是否存在。
2. 要删除的节点是页节点。
3. 要删除的节点的左子树存在。
4. 要删除的节点的右子树存在。
5. 要删除的节点的左右子树都存在。
6. 要删除的节点不存在。

第一种和第六种情况可以直接返回。
第二种情况直接对节点进行删除。
对于第三种情况:
我们将它的左子树与该节点的父节点的左/右(该节点所在位置)相连,然后删除该节点即可。
对于第四中情况的处理方式与第三中相同。
这里写图片描述这里写图片描述
对于第五种情况我们不可以直接对该点进行删除
我们可以将该点与其左子树中的最大值进行交换(左子树的最右树),然后就像删除页节点一样可以直接进行删除。
这里写图片描述

在以上的删除情况中我们都要对如果删除的节点是根节点进行判断,否则程序会出现崩溃情况.

实现:

bool Remove(const K& key) {   //删除
        if (_root == NULL)
            return false;
        // 删除后应该将其父亲的该节点置空
        //  cur parent
        // 替换删除 该节点左树中最大的/右数中最小的    
        Node *parent = NULL;
        Node *cur = _root;
        while (cur) {
            if (cur->_key < key){
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                parent = cur;
                cur = cur->_left;
            }
            else{   //找到了
                // 1.  左为空
                // 2.  左不为空 右为空
                // 3.  左右都不为空
                Node *del = cur;
                if (cur->_left == NULL) {
                    if (parent == NULL)
                        _root = cur->_right;
                    else {
                        if (cur == parent->_right)
                            parent->_right = cur->_right;
                        else
                            parent->_left = cur->_right;
                    }
                }
                else if (cur->_right == NULL){
                    if (parent == NULL)
                        _root = cur->_left;
                    else {
                        if (cur == parent->_right)
                            parent->_right = cur->_left;
                        else
                            parent->_left = cur->_left;
                    }
                }
                else{ //找左树的最右节点或者    **右树的最左节点
                    Node *parent = cur;
                    Node *subLeft = cur->_right;
                    while (subLeft->_left) {
                        parent = subLeft;
                        subLeft = subLeft->_left;
                    }
                    cur->_key = subLeft->_key;
                    del = subLeft;
                    // 不可以直接让parent 的左 指向 cur 的右
                    if (parent->_left == subLeft)
                        parent->_left = subLeft->_right;
                    else
                        parent->_right = subLeft->_left;
                }
                delete del;
                return true;
            }
        }
        return false;

    }

查找:
根据左树比根节点小,右树比根节点大的特点进行查找

实现:

    Node * Find(const K& key) {  //查找
        if (_root == NULL)
            return NULL;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key)
                cur - cur->_left;
            else if (cur->_key < key)
                cur = cur->_right;
            else
                return cur;
        }
        return NULL;
    }

这里写图片描述
由这张图我们可以发现,查询的时间复杂度大致为 O(log(N))
但是,当我们所获得的搜索二叉树是一个单支树时,查询的时间复杂度则会变为 O(N)
所以搜索二叉树的时间复杂度大致在 O(log(N))~O(N)之间,这种情况将在平衡搜索二叉树中解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值