当前位置: 首页 > article >正文

C++笔记——第十二篇 二叉搜索树

                    

 

目录

一、二叉搜索树概念

二、二叉搜索树操作 

1. 二叉搜索树的查找

2. 二叉搜索树的插入

a. 树为空,则直接插入,返回true

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点 

3. 二叉搜索树的删除

情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点

情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点

情况d:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置,并返回删除节点右孩子为新的根节点。见下图

递归的代码

4 二叉搜索树的应用

5 二叉搜索树的性能分析


 



一、二叉搜索树概念



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


若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树



二、二叉搜索树操作 



1. 二叉搜索树的查找


 


2. 二叉搜索树的插入


a. 树为空,则直接插入,返回true

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点 

 


3. 二叉搜索树的删除


首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点


看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:


情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的孩子结点

 



情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的孩子结点


 


情况d:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置,并返回删除节点右孩子为新的根节点。见下图

 

 


递归的代码

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
        if (root->val == key) {
            // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
            if (root->left == nullptr && root->right == nullptr) {
                ///! 内存释放
                delete root;
                return nullptr;
            }
            // 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
            else if (root->left == nullptr) {
                auto retNode = root->right;
                ///! 内存释放
                delete root;
                return retNode;
            }
            // 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
            else if (root->right == nullptr) {
                auto retNode = root->left;
                ///! 内存释放
                delete root;
                return retNode;
            }
            // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
            // 并返回删除节点右孩子为新的根节点。
            else {
                TreeNode* cur = root->right; // 找右子树最左面的节点
                while(cur->left != nullptr) {
                    cur = cur->left;
                }
                cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                TreeNode* tmp = root;   // 把root节点保存一下,下面来删除
                root = root->right;     // 返回旧root的右孩子作为新root
                delete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
                return root;
            }
        }
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

4 二叉搜索树的应用


1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以单词集合中的每个单词作为key,构建一棵二叉搜索树
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

(这就是set!当然,set用的是对二叉搜索树的扩展——红黑树!以后就会讲到!)


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

比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。
比如:实现一个简单的英汉词典dict,可以通过英文找到与其对应的中文,具体实现方式如下:
<单词,中文含义>为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较
Key。
查询英文单词时,只需给出英文单词,就可快速找到与其对应的key

(这就是map!当然它用的也是红黑树)


5 二叉搜索树的性能分析



插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树。

左边为最好情况,平均比较次数 logN

右边为最差情况,就成了单链表了, 效率下降, 平均比较次数 N/2


这里放一下二叉树的做题个人总结:自用版

递归参数,返回值

递归出口

单层递归

二叉树:

1.是否要返回值

整个树需要处理节点 后序:left=dfs(); right=dfs(); 中间--> 处理left和right的逻辑

整个树不需要处理返回值

遍历一条边 通常是二叉搜索树, if(dfs(left)) return;    if(dfs(right)) return;  

2.确定遍历方式

前序:构造树;求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径;深度

中序:搜索树有序 

后序:回溯;高度;普通二叉树的属性;要通过递归函数的返回值来累加求取左叶子数值之和

3.构造树

切割,分成左数组,右数组


                        

 

 


http://www.kler.cn/a/6071.html

相关文章:

  • 优化提示词改善答疑机器人回答质量
  • Ubuntu上安装Apache Spark
  • 【杂谈】-50+个生成式人工智能面试问题(一)
  • n 维数组(张量)关于轴 axis 的理解
  • Qt 5.14.2 学习记录 —— 오 信号与槽机制(2)
  • 5.1 数据库:INSERT 插入语句
  • 【对比学习(二)】如何得到正负样本?下游任务的具体执行阶段(以特斯拉为例简要讲解)?你知道什么是“模型坍塌”么?【NLP】中该如何做对比学习?
  • 初识Matlab2012a的神经网络工具箱(1)
  • 【LeetCode】二叉树的中序遍历(递归,迭代,Morris遍历)
  • SELECT COUNT(*) 会造成全表扫描吗
  • Disjoint 集合数据结构或 Union-Find 算法简介
  • jsp823科研项目申报管理网站cc94程序mysql+java
  • Uni-Mol: A Universal 3D Molecular Representation Learning Framework
  • 使用new bing chat成功了
  • 华为OD机试用java实现 -【数字的排列 or 数字反转打印】
  • CRM客户管理系统不被销售接受的五大原因
  • 二、MySQL 基础
  • 【软考——系统架构师】系统开发基础知识
  • 如何保证RocketMQ顺序消息以及可能出现的问题
  • Databend 开源周报第 86 期
  • 【CSS】清除浮动 ① ( 清除浮动简介 | 清除浮动语法 | 清除浮动 - 额外标签法 )
  • 计算机组成原理:5. 输入输出系统
  • Higress 0.7.0 版本发布:GA 进入倒计时
  • 学会吊打面试官之list
  • 通过两道一年级数学题反思自己
  • LeetCode222. 完全二叉树的节点个数(二分查找+二进制表示路径法)