第十四章:二叉搜索树

第十四章:二叉搜索树

1.二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

  • 它的左右子树也分别为二叉搜索树

2.二叉搜索树的实现

#include<iostream>
using namespace std;

template<class K>
struct BSTNode
{
    BSTNode(const K& key = K())
        :_left(nullptr)
        ,_right(nullptr)
        ,_key(key)
    {}  
    BSTNode<K>* _left;
    BSTNode<K>* _right;
    K _key;
};

template<class K>
class BSTree
{
    typedef BSTNode<K> Node;
public:
    BSTree()
        :_root(nullptr)
    {}

    BSTree(const BSTree<K>& t)
    {
        _root = _Copy(t._root);
    }

    BSTree<K>& operator=(const BSTree<K>& t)
    {
        swap(_root, t._root);
        return *this;
    }

    ~BSTree()
    {
        _Destory(_root);
    }

    //递归插入
    bool InsertR(const K& key)
    {
        return _InsertR(_root, key);
    }

    //递归查找
    Node* FindR(const K& key)
    {
        return _FindR(_root, key);
    }

    //递归删除
    bool EraseR(const K& key) 
    {
        return _EraseR(_root, key);
    }

    bool Insert(const K& key)
    {
        if (_root == nullptr)
        {
            _root = new Node(key);
            return true;
        }
        Node* pre_cur = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key < key) {
                pre_cur = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                pre_cur = cur;
                cur = cur->_left;
            }
            else {
                return false;
            }
        }
        cur = new Node(key);
        if (pre_cur->_key < key) {
            pre_cur->_right = cur;
        }
        else {
            pre_cur->_left = cur;
        }
        return true;
    }

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

    //删除
    bool Erase(const K& key)
    {
        //空二叉树
        if (_root == nullptr)
        {
            return false;
        }
        //查找
        Node* pre_cur = nullptr;
        Node* cur = _root;
        while (cur!=nullptr)
        {
            if (cur->_key < key) {
                pre_cur = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key) {
                pre_cur = cur;
                cur = cur->_left;
            }
            else {
                //找到了
                if (cur->_left == nullptr)
                {
                    //左子树为空或者左、右子树都空
                    if (cur == _root)//要删除的节点为根节点
                    {
                        _root = cur->_right;
                        delete cur;
                        cur = nullptr;
                    }
                    else
                    {
                        if (pre_cur->_left == cur)
                        {
                            pre_cur->_left = cur->_right;
                        }
                        else
                        {
                            pre_cur->_right = cur->_right;
                        }
                        delete cur;
                        cur = nullptr;
                    }
                    
                }
                else if (cur->_right == nullptr)
                {
                    //只有右子树为空
                    if (cur == _root)//要删除的节点为根节点
                    {
                         _root = cur->_left;
                        delete cur;
                        cur = nullptr;
                    }
                    else
                    {
                        if (pre_cur->_left == cur)
                        {
                            pre_cur->_left = cur->_left;
                        }
                        else
                        {
                            pre_cur->_right = cur->_left;
                        }
                        delete cur;
                        cur = nullptr;
                    }
                }
                else
                {
                    //左右都不为空,找右子树最小的节点
                    Node* pre_min_right = cur;
                    Node* min_right = cur->_right;
                    while (min_right->_left)
                    {
                        pre_min_right = min_right;
                        min_right = min_right->_left;
                    }
                    cur->_key = min_right->_key;
                    if (pre_min_right->_left == min_right)
                    {
                        pre_min_right->_left = min_right->_right;
                    }
                    else
                    {
                        pre_min_right->_right = min_right->_right;
                    }
                    delete min_right;
                    min_right = NULL;
                }
            }
        }
        return false;
    }

    //递归中序遍历
    void InOrder()
    {
        if (_root == nullptr)
        {
            cout << "树空!" << endl;
        }
        _InOrder(_root);
        cout << endl;
    }

private:
    Node* _root;

    //删除
    void _Destory(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }
        _Destory(root->_left);
        _Destory(root->_right);
        delete root;
        root = nullptr;
    }

    //复制
    Node* _Copy(Node* root)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        Node* copyNode = new Node(root->_key);
        copyNode->_left = _Copy(root->_left);
        copyNode->_right = _Copy(root->_right);
        return copyNode;
    }

    //递归插入
    bool _InsertR(Node*& root, const K& key)
    {
        if (root == nullptr)
        {
            root = new Node(key);
            return true;
        }
        if (root->_key < key)
        {
            return _InsertR(root->_right, key);
        }
        else if (root->_key > key)
        {
            return _InsertR(root->_left, key);
        }
        else 
        {
            return false;
        }
    }

    //递归查找
    Node* _FindR(Node* root, const K& key)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        if (root->_key < key)
        {
            return _FindR(root->_right, key);
        }
        else if (root->_key > key)
        {
            return _FindR(root->_left, key);
        }
        else
        {
            return root;
        }
    }

    //递归删除
    bool _EraseR(Node*& root, const K& key)
    {
        if (root == nullptr)
        {
            return false;
        }
        if (root->_key < key)
        {
            return _EraseR(root->_right, key);
        }
        else if (root->_key > key)
        {
            return _EraseR(root->_left, key);
        }
        else
        {
            //找到了
            if (root->_left == nullptr)
            {
                Node* del = root;
                root = root->_right;
                delete del;
                del = nullptr;
            }
            else if (root->_right == nullptr)
            {
                Node* del = root;
                root = root->_left;
                delete del;
                del = nullptr;
            }
            else
            {
                Node* pre_min_right = root;
                Node* min_right = root->_right;
                while (min_right->_left)
                {
                    pre_min_right = min_right;
                    min_right = min_right->_left;
                }
                root->_key = min_right->_key;
                if (pre_min_right->_left == min_right)
                {
                    pre_min_right->_left = min_right->_right;
                }
                else
                {
                    pre_min_right->_right = min_right->_right;
                }
                delete min_right;
                min_right = NULL;
            }
        }
        return false;
    }

    //递归中序遍历
    void _InOrder(Node* root)
    {
        if (root == nullptr)
            return;
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }
};

3.二叉搜索树的应用

K模型K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值

比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以单词集合中的每个单词作为key,构建一棵二叉搜索树

  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

KV模型每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对

该种方式在现实生活中非常常见:比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。

比如:实现一个简单的英汉词典dict,可以通过英文找到与其对应的中文,具体实现方式如下:

  • <单词,中文含义>为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较Key

  • 查询英文单词时,只需给出英文单词,就可快速找到与其对应的key

//kv和k类似,在前面实现的基础上进行了一定程度的改造
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

template<class K,class V>
struct BSTNode
{
    BSTNode(const K& key, const V& value)
        :_left(nullptr)
        , _right(nullptr)
        , _key(key)
        ,_value(value)
    {}
    BSTNode<K,V>* _left;
    BSTNode<K,V>* _right;
    K _key;
    V _value;
};

template<class K,class V>
class BSTree
{
    typedef BSTNode<K,V> Node;
public:
    BSTree()
        :_root(nullptr)
    {}

    BSTree(const BSTree<K,V>& t)
    {
        _root = _Copy(t._root);
    }

    BSTree<K,V>& operator=(const BSTree<K,V>& t)
    {
        swap(_root, t._root);
        return *this;
    }

    ~BSTree()
    {
        _Destory(_root);
    }

    //递归插入
    bool InsertR(const K& key,const V& value)
    {
        return _InsertR(_root, key, value);
    }

    //递归查找
    Node* FindR(const K& key)
    {
        return _FindR(_root, key);
    }

    //递归删除
    bool EraseR(const K& key)
    {
        return _EraseR(_root, key);
    }

    //递归中序遍历
    void InOrder()
    {
        if (_root == nullptr)
        {
            cout << "树空!" << endl;
        }
        _InOrder(_root);
        cout << endl;
    }

private:
    Node* _root;

    //删除
    void _Destory(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }
        _Destory(root->_left);
        _Destory(root->_right);
        delete root;
        root = nullptr;
    }

    //复制
    Node* _Copy(Node* root)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        Node* copyNode = new Node(root->_key, root->_value);
        copyNode->_left = _Copy(root->_left);
        copyNode->_right = _Copy(root->_right);
        return copyNode;
    }

    //递归插入
    bool _InsertR(Node*& root, const K& key,const V& value)
    {
        if (root == nullptr)
        {
            root = new Node(key, value);
            return true;
        }
        if (root->_key < key)
        {
            return _InsertR(root->_right, key, value);
        }
        else if (root->_key > key)
        {
            return _InsertR(root->_left, key, value);
        }
        else
        {
            return false;
        }
    }

    //递归查找
    Node* _FindR(Node* root, const K& key)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        if (root->_key < key)
        {
            return _FindR(root->_right, key);
        }
        else if (root->_key > key)
        {
            return _FindR(root->_left, key);
        }
        else
        {
            return root;
        }
    }

    //递归删除
    bool _EraseR(Node*& root, const K& key)
    {
        if (root == nullptr)
        {
            return false;
        }
        if (root->_key < key)
        {
            return _EraseR(root->_right, key);
        }
        else if (root->_key > key)
        {
            return _EraseR(root->_left, key);
        }
        else
        {
            //找到了
            if (root->_left == nullptr)
            {
                Node* del = root;
                root = root->_right;
                delete del;
                del = nullptr;
            }
            else if (root->_right == nullptr)
            {
                Node* del = root;
                root = root->_left;
                delete del;
                del = nullptr;
            }
            else
            {
                Node* minRight = root->_right;
                while (minRight->_left)
                {
                    minRight = minRight->_left;
                }
                K kmin = minRight->_key;
                V vmin = minRight->_value;
                _EraseR(root->_right, kmin);
                root->_key = kmin;
                root->_value = vmin;
            }
        }
        return false;
    }

    //递归中序遍历
    void _InOrder(Node* root)
    {
        if (root == nullptr)
            return;
        _InOrder(root->_left);
        cout << root->_key << "---" << root->_value << "  ";
        _InOrder(root->_right);
    }
};

void test1()//功能测试
{
    BSTree<int, int> t;
    int key[] = { 5,3,4,1,7,8,2,6,0,9 };
    int value[] = { 1,2,3,4,5,6,7,8,9,10 };
    for (size_t i = 0; i < 10; ++i)
    {
        t.InsertR(key[i], value[i]);
    }
    t.InOrder();
    BSTree<int, int> t1(t);
    BSTree<int, int> t2 = t;
    t1.InOrder();
    t2.InOrder();
    BSTNode<int, int>* newnode = t.FindR(5);
    cout << newnode->_key << "---" << newnode->_value << endl;
    for (auto e : key)
    {
        t.EraseR(e);
    }
    t.InOrder();
}

void test2()//简单翻译
{
    BSTree<string, string> dict;
    dict.InsertR("string", "字符串");
    dict.InsertR("tree", "树");
    dict.InsertR("left", "左边");
    dict.InsertR("right", "右边");
    dict.InsertR("sort", "排序");
    dict.InsertR("dragon", "龙");
    
    string str;
    while (cin >> str)
    {
        BSTNode<string, string>* ret = dict.FindR(str);
        if (ret == nullptr)
        {
            cout << "单词拼写错误或者词库中未收录!" << endl;
        }
        else
        {
            cout << "中文翻译:" << ret->_value << endl;
        }
    }
}

void test3()//计数器
{
    string arr[] = { "苹果","苹果","菠萝","香蕉","苹果","苹果","西瓜","苹果" };
    BSTree<string, int> countTree;
    for (const auto& str : arr)
    {
        auto ret = countTree.FindR(str);
        if (ret == nullptr)
        {
            countTree.InsertR(str, 1);
        }
        else
        {
            ret->_value++;
        }
    }
    countTree.InOrder();
}

4.二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log₂N

最差情况下,二叉搜索树退化为单支树,其平均比较次数为: N/2

如果退化成单支树,二叉搜索树的性能就失去了,所以为了提高二叉搜索树操作的效率,在构建二叉搜索树时尽量避免出现单支树的情况出现,通过一些机制是可以避免在构建二叉树时出现单支树的情况,例如:平衡二叉搜索树。

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值