C : DS二叉排序树之删除(详细思路解答)

Description

给出一个数据序列,建立二叉排序树,并实现删除功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

Input

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要删除m个数据

从第五行起,输入m行,每行一个要删除的数据,都是自然数

以此类推输入下一个示例

Output

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出删除第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

Sample

Hint

当删除数据不在序列中,那么删除操作等于不执行,所以输出序列不变化

分析:删除的节点有三种情况。

  1. 叶子节点,即没有左子树和右子树

  2. 只有右子树或者只有左子树

  3. 同时有左右子树

思路:

        创建deleteNode方法,deleteNode(BinaryTreeNode*& t, int deleteNumber),传入参数为根节点以及删除的值。

 值相等之后进行判断

第一个判断:

左子树为空(包含叶子节点的情况,左右子树同时为空,右子树为NULL,temp会保存NULL,最后t被替换成NULL,相当于删除了叶子节点)

第二个判断:

右子树为空,左子树不为空。操作同上

 第三个判断:

左右子树都不为空。先找到右子树上最小节点,于是用函数BinaryTreeNode* findMinNode(BinaryTreeNode* t)进行寻找,进入右子树之后,当前节点不存在左子树时即为最小值。t为当前要删除的节点,用右子树上最小节点值替换当前节点值。替换值完成后进入右子树,重新调用deleteNode删除掉右子树最小节点即完成替换。

 例如:

最关键的是要对二叉排序树的性质要熟悉,左子树上所有的值都小于根节点,右子树上所有的值都大于根节点。

AC代码:

#include <iostream>
using namespace std;

struct BinaryTreeNode {
    int data;
    BinaryTreeNode* left;
    BinaryTreeNode* right;
    BinaryTreeNode() {
        data = 0;
        left = NULL;
        right = NULL;
    }
};

class BinaryTree {
public:
    BinaryTreeNode* root;

    BinaryTree() {
        root = nullptr;
    }

    ~BinaryTree() {
        destroyTree(root);
    }

    void init(BinaryTreeNode*& t, int data) {
        if (t) {
            if (data > t->data && t->right) {
                init(t->right, data);
            }
            else if (data < t->data && t->left) {
                init(t->left, data);
            }
            else if (data == t->data) {
                return;
            }
            if (data > t->data && t->right == NULL) {
                BinaryTreeNode* newNode = new BinaryTreeNode;
                newNode->data = data;
                t->right = newNode;
            }
            else if (data < t->data && t->left == NULL) {
                BinaryTreeNode* newNode = new BinaryTreeNode;
                newNode->data = data;
                t->left = newNode;
            }
        }
        else {
            t = new BinaryTreeNode;
            t->data = data;
        }
    }

    void midTree(BinaryTreeNode* t) {
        if (t) {
            midTree(t->left);
            cout << t->data << " ";
            midTree(t->right);
        }
    }

    void deleteNode(BinaryTreeNode*& t, int deleteNumber) {
        if (t == nullptr) {
            return;
        }
        //通过删除值与当前节点值进行比较,进行递归处理,直到值相等。
        if (deleteNumber > t->data) {
            deleteNode(t->right, deleteNumber);
        }
        else if (deleteNumber < t->data) {
            deleteNode(t->left, deleteNumber);
        }
        else {
            if (t->left == nullptr) {//左子树为空(包含叶子节点的情况,左右子树同时为空,右子树为NULL,temp会保存NULL,最后t被替换成NULL,相当于删除了叶子节点)
                BinaryTreeNode* temp = t->right;//临时节点保存右子树
                delete t;//删除当前节点
                t = temp;//用右子树替换当前节点
            }
            else if (t->right == nullptr) {//右子树为空,左子树不为空。操作同上
                BinaryTreeNode* temp = t->left;
                delete t;
                t = temp;
            }
            else {//左右子树都不为空。
                //找到右子树上最小节点
                BinaryTreeNode* minNode = findMinNode(t->right);
                //t为当前要删除的节点,用右子树上最小节点值替换当前节点值。
                t->data = minNode->data;
                deleteNode(t->right, minNode->data);//然后进入右子树,删除掉右子树最小节点即完成替换。
            }
        }
    }

    BinaryTreeNode* findMinNode(BinaryTreeNode* t) {
        while (t->left != nullptr) {
            t = t->left;
        }
        return t;
    }

    void destroyTree(BinaryTreeNode* t) {
        if (t) {
            destroyTree(t->left);
            destroyTree(t->right);
            delete t;
        }
    }
};

int main() {
    int t;
    cin >> t;

    while (t--) {
        int n;
        cin >> n;
        BinaryTree p;
        while (n--) {
            int data;
            cin >> data;
            p.init(p.root, data);
        }
        p.midTree(p.root);
        cout << endl;

        int deleteTimes;
        cin >> deleteTimes;
        while (deleteTimes--) {
            int deleteNum;
            cin >> deleteNum;
            p.deleteNode(p.root, deleteNum);
            p.midTree(p.root);
            cout << endl;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/257034.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习:增强式学习Reinforcement learning

收集有标签数据比较困难的时候同时也不知道什么答案是比较好的时候可以考虑使用强化学习通过互动&#xff0c;机器可以自己知道什么结果是好的&#xff0c;什么结果是坏的 Outline 什么是RL Action就是一个functionEnvironment就是告诉这个Action是好的还是坏的 例子 Space i…

01-从JDK源码级别彻底剖析JVM类加载机制

文章目录 类加载运行全过程类加载器和双亲委派机制类加载器初始化过程双亲委派机制为什么要设计双亲委派机制&#xff1f;全盘负责委托机制自定义类加载器 打破双亲委派机制Tomcat打破双亲委派机制Tomcat自定义加载器详解模拟实现Tomcat的JasperLoader热加载 补充&#xff1a;H…

二进制枚举算法

二进制 : 也就是只有0和1的进制表示 ; 二进制枚举算法 一个二进制数 x 可以表示 S 的一个子集&#xff0c;某个二进制位i上为0表示没有选i元素&#xff0c;为1表示选了该元素放入子集,比如13为1101就表示选了0,2,3号元素;对于一个长度为N的序列(也就是包含N个元素)有2^N个子…

建筑模板怎么选?

在建筑领域&#xff0c;选择合适的模板材料对于确保工程质量、提高施工效率和控制成本至关重要。目前&#xff0c;常见的建筑模板主要有钢模板、塑料模板和木模板三种类型&#xff0c;每种都有其独特的优势和局限性。本文将对这些模板类型进行分析&#xff0c;并特别推荐广西生…

沉浸式数字文旅黑科技!用AI数字人升级景区体验

这年头文旅界也太卷了&#xff01; 在国家文化数字化战略的深入实施下&#xff0c;各地方文旅纷纷打造新型消费场景&#xff0c;以数字文旅提升消费产品的互动性和社交性&#xff0c;增强用户沉浸式体验。 其中&#xff0c;数字人乘着AI大语言模型的东风&#xff0c;被文旅品牌…

【数据结构】使用循环链表结构实现约瑟夫环问题

目录 1.循环链表的定义 2.约瑟夫环问题 3.创建循环链表 4.删除节点操作 5.打印所有节点 6.实现约瑟夫环问题的完整程序代码 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo_…

OpenAI 增强安全团队并赋予董事会对危险人工智能的否决权

OpenAI 在扩展其内部安全流程方面的举措以应对有害 AI 的威胁&#xff0c;OpenAI高层推出了一份更新的“准备框架”。OpenAI 的目标是识别、分析和决定如何应对他们正在开发的模型中的“灾难性”风险。他们通过对模型的四个风险类别进行评估&#xff0c;并根据风险级别制定相应…

在Android手机设置中启动ESIM

eSIM测试配置文件仅用于实验室测试。 1.到“设置”->“网络和互联网”->“SIM”&#xff0c;确认没有eSIM配置文件。 2.启动拨号程序&#xff0c;然后按短代码****#3746878#**#*&#xff08;****#ESIMTEST#**#**&#xff09; 有一个弹出通知“eSIM测试模式已启用” 3.返…

【JavaScript设计模式】Singleton Pattern

单例是可以被实例化一次的类&#xff0c;并且可以被全局访问。这个实例可以在整个应用程序中共享&#xff0c;这使得singleton非常适合管理应用程序中的全局状态。 首先&#xff0c;让我们看看使用ES2015类的单例是什么样子的。在这个例子中&#xff0c;我们将构建一个Counter…

ASP.NET MVC+EntityFramework图片头像上传

1&#xff0c;先展示一下整体的效果 2&#xff0c;接下来展示用户添加以及上传头像代码、添加用户界面 前端代码如下&#xff1a; <div class"form-group">Html.LabelFor(model > model.img, "头像&#xff1a;", htmlAttributes: new { class &…

【Linux】ip命令使用

ip命令 用于管理与配置网络接口和路由表。 ip命令的安装 ip 命令来自 iproute2 软件包&#xff0c;在 CentOS 7 中默认已安装。 yum install -y iproute 语法 ip [ OPTIONS ] OBJECT { COMMAND | help }ip [ -force ] -batch filename选项及作用 执行令 &#xff1a; ip …

计算机组成原理第4章-(存储器)【上】

存储器分类 对于计算机中存储器的分类&#xff0c;方法有很多&#xff0c;不同的方法之间是独立的&#xff0c;为此我们简单讲述两种分类 方法&#xff1a;“存取方式分类”、“在计算机中作用分类”。 -->按存取方式分类 按存取方式分类可以将存储器分为&#xff1a;“…

水经微图Web新版发布

水经微图Web新版已经上线&#xff0c;在该版本中主要新增了态势箭头标绘、文本要素标注和显示网页气泡等功能。 在本文中&#xff0c;我们将为大家分享新增的功能项&#xff0c;以及原有功能作的一些优化等。 当前版本 当前版本号为&#xff1a;1.4.0-beta 如果你发现该版…

JavaSE 泛型

目录 1 泛型类的定义1.1 为什么需要泛型1.2 泛型的概念1.3 泛型的分类 2 泛型类2.1 泛型类的定义2.2 泛型类的例子2.3 泛型类的实例化2.3.1 实例化语法2.3.2 裸类型(Raw Type) 2.4 泛型类的定义-类型边界2.5 泛型类的使用-通配符(Wildcards)2.5.1 基本概念2.5.2 通配符-上界2.5…

14、Kafka 请求是怎么被处理的

Kafka 请求是怎么被处理的 1、处理请求的 2 种常见方案1.1、顺序处理请求1.2、每个请求使用单独线程处理 2、Kafka 是如何处理请求的&#xff1f;3、控制类请求和数据类请求分离 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过 “请求 / 响应” 的方式完…

Hypervisor Display架构

Hypervisor Display架构部分 1&#xff0c;所有LA侧的APP与显示相关的调用最终都会交由SurfaceFlinger处理 2&#xff0c;SurfaceFlinger会最终调用android.hardware.graphics.composer2.4-service服务 3&#xff0c;android.hardware.graphics.composer2.4-service服务会调用G…

针对企业的泄密,天锐绿盾提出十大解决方案

01 防止公司内部数据泄密 通过动态加解密技术&#xff0c;有效防止公司内部数据泄密。即员工在创建、编辑文档时会被自动加密存放在硬盘上&#xff0c;防止员工故意或由于疏忽而造成泄密或对文件恶意破坏。 管理思路>> ● 不改变员工使用习惯、不改变文件格式、不改变…

APM固件编译和仿真

事情起因 主要想对无人机APM固件进行仿真的算法验证&#xff0c;因实际飞行的过程实际验证太浪费飞机了&#xff0c;所以就先试用仿真对算法进行仿真开发。 一&#xff0c;环境搭建 环境搭建我建议参考官方英文教程&#xff0c;英文教程写的比较全&#xff0c;不懂可以自己使…

科聪控制系统典型应用车型 —— 料箱机器人

料箱机器人即料箱AGV是一种智能化物流搬运设备&#xff0c;它可以代替人力完成出库入库和搬运工作&#xff0c;可根据出入库生产出货需求&#xff0c;将货物从起点运送到终点&#xff0c;自动柔性完成货到人货到点的操作。 提升仓储和物流效率的自动化利器 料箱机器人的投用能…

yolov5单目测距+速度测量+目标跟踪(算法介绍和代码)

要在YOLOv5中添加测距和测速功能&#xff0c;您需要了解以下两个部分的原理&#xff1a; 单目测距算法 单目测距是使用单个摄像头来估计场景中物体的距离。常见的单目测距算法包括基于视差的方法&#xff08;如立体匹配&#xff09;和基于深度学习的方法&#xff08;如神经网…