【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(二)

简介: 【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现

【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(一)https://developer.aliyun.com/article/1617404


2.5.3 第三种情况(替换法)

使用替换法删除,简单回顾

  • 左子树上所有节点的值都小于根节点的值
  • 右子树上所有节点的值都大于根节点的值

被替换的节点需要满足左子树最大节点或者右字数的最小节点其中之一即可。比如满足左子树最大节点,进行交换,该节点满足比左子树都要大,比右子树都要小。

替换法删除的具体流程:

  • 先找到需要被删除节点和被替换节点,进行swap交换数字
  • 通过第一、二种情况进行删除操作
  • 那么需要设置两个指针去需要被替换节点
Node* RightMinParent = cur;
Node* RightMin = cur->_right;
//找到右子树最小的值
while (RightMin->_left)
{
    RightMinParent = RightMin;
    RightMin = RightMin->_left;
}
//找到
swap(cur->_key, RightMin->_key);
if (RightMinParent->_left == RightMin)
{
    RightMinParent->_left = RightMin->_right;
}
else
{
    RightMinParent->_right = RightMin->_right;
}
delete RightMin;
}
return true;

实现该逻辑的具体细节:

  • 这里我选择找到右子树的最小节点,那么只需要关注左边的情况就行了,这也是为什么是while (RightMin->_left)
  • 首先就是第一、二种情况删除的做法
  • RightMinParent不能设置为空指针当删除根节点就会有问题,直接设置为cur

以上三种情况都需要考虑需要被删除节点为根节点

2.6 采用中序遍历二叉搜索树

void InOrder()
{
    _InOrder(_root);
    cout << endl;
}
private:
void _InOrder(Node* root)
{
    if (root == nullptr)
    {
        return;
    }
    _InOrder(root->_left);
    cout << root->_key << " ";
    _InOrder(root->_right);
}

中序遍历能够按顺序输出树中所有节点的值。从根节点开始,中序遍历的顺序是【左子树 , 根节点 , 右子树】这一过程在BST中恰好能保证节点按从小到大的顺序排列。将内部实现放在private部分,可以避免外部代码错误地调用内部方法,导致程序行为不可预测或出错。通过控制访问权限。外部代码不应该直接操作树的节点,而应该通过公开的接口方法来访问和操作树。

三、改造二叉搜索树,进行实际应用

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

使用场景:判断单词是否拼写正确

  • 将词库中所有单词集合中的每个单词作为key,构建一颗二叉搜索树
  • 在二叉搜索树中查找单词是否存在,存在则为正确,否则错误

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

使用场景:翻译语言(底层主要还是B树)

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是就构成一种键值对
// 改造二叉搜索树为KV结构
template<class K, class V>
    struct BSTNode
    {
        BSTNode(const K& key = K(), const V& value = V())
            : _pLeft(nullptr) , _pRight(nullptr), _key(key), _Value(value)
            {}
        BSTNode<T>* _pLeft;
        BSTNode<T>* _pRight;
        K _key;
        V _value
    };
template<class K, class V>
    class BSTree
    {
        typedef BSTNode<K, V> Node;
        typedef Node* PNode;
        public:
        BSTree(): _pRoot(nullptr){}
        PNode Find(const K& key);
        bool Insert(const K& key, const V& value)
            bool Erase(const K& key)
            private:
        PNode _pRoot;
    };
void TestBSTree3()
{
    // 输入单词,查找单词对应的中文翻译
    BSTree<string, string> dict;
    dict.Insert("string", "字符串");
    dict.Insert("tree", "树");
    dict.Insert("left", "左边、剩余");
    dict.Insert("right", "右边");
    dict.Insert("sort", "排序");
    // 插入词库中所有单词
    string str;
    while (cin>>str)
    {
        BSTreeNode<string, string>* ret = dict.Find(str);
        if (ret == nullptr)
        {
            cout << "单词拼写错误,词库中没有这个单词:" <<str <<endl;
        }
        else
        {
            cout << str << "中文翻译:" << ret->_value << endl;
        }
    }
}
void TestBSTree4()
{
    // 统计水果出现的次数
    string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
                    "苹果", "香蕉", "苹果", "香蕉" };
    BSTree<string, int> countTree;
    for (const auto& str : arr)
    {
        // 先查找水果在不在搜索树中
        // 1、不在,说明水果第一次出现,则插入<水果, 1>
        // 2、在,则查找到的节点中水果对应的次数++
        //BSTreeNode<string, int>* ret = countTree.Find(str);
        auto ret = countTree.Find(str);
        if (ret == NULL)
        {
            countTree.Insert(str, 1);
        }
        else
        {
            ret->_value++;
        }
    }
    countTree.InOrder();
}

四、二叉搜索树的性能分析

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

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

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

  • 最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树)
  • 最差情况下,二叉搜索树退化为单支树(或者类似单支)

如果退化成单支树,二叉搜索树的性能就失去了 ,我们后续章节学习的AVL树和红黑树就可以上场了


【高阶数据结构】深度探索二叉树进阶:二叉搜索树概念及其高效实现(三)https://developer.aliyun.com/article/1617406

相关文章
|
4月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
105 10
 算法系列之数据结构-二叉树
|
4月前
|
算法 Java
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
115 22
|
4月前
|
C语言 C++ 容器
【数据结构】二叉搜索树(二叉排序树)
本文介绍了二叉搜索树(Binary Search Tree, BST)的定义、实现及其性能分析。二叉搜索树是一种特殊的二叉树,其特点是左子树所有节点值小于根节点值,右子树所有节点值大于根节点值,且每个子树也满足此特性。文中详细讲解了BST的节点结构、插入、查找、删除等操作的实现,并通过C++代码展示了这些功能。此外,还讨论了BST的性能:在理想情况下,时间复杂度接近O(logN),但在最坏情况下可能退化为O(N)。为了提高效率,后续将学习自平衡二叉搜索树如AVL树和红黑树。掌握BST有助于理解STL中的set和map容器。感谢阅读,欢迎点赞支持。
305 9
|
6月前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
156 12
|
6月前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
145 10
|
6月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
212 3
|
7月前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
8月前
|
机器学习/深度学习 存储 算法
数据结构实验之二叉树实验基础
本实验旨在掌握二叉树的基本特性和遍历算法,包括先序、中序、后序的递归与非递归遍历方法。通过编程实践,加深对二叉树结构的理解,学习如何计算二叉树的深度、叶子节点数等属性。实验内容涉及创建二叉树、实现各种遍历算法及求解特定节点数量。
234 4
|
8月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
186 59
|
1月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
24 0
栈区的非法访问导致的死循环(x64)