西南交通大学【数据结构实验8】

实验内容及要求: 

编写控制台应用程序,提供以下菜单项:

  1. 插入元素

从键盘输入若干两两互不相同的非0整数,直到输入0时停止。将输入的所有非0整数按输入次序插入二叉排序树(初始时是空树)。

插入某个非0整数时,若该整数已在二叉排序树中,则插入该整数失败(应显示提示信息)。

全部整数插入结束后,显示成功插入的整数个数。

  1. 删除元素

输入一个整数,若它在二叉排序树中,则删除它(提示删除成功与失败)。

  1. 输出

输出二叉排序树的先序和中序递归遍历结点访问次序。

  1. 结束程序

实验目的:掌握二叉排序树插入、删除元素的基本算法。

数据结构设计简要描述:

将int型作为此次实验的关键字,通过自定义二叉排序树节点结构存储二叉排序树

// 将int作为元素类型

typedef int elem;

// 自定义二叉排序树节点类型

typedef struct node

{

     elem data;

     // 左子树 右子树

     struct node* lchild, * rchild;

}BSTNode, * BSTree;

算法设计简要描述:

创建二叉排序树采用逐个读取value值创建二叉排序树节点,然后逐个插入进二叉树。在插入时先判断此节点的值是否已存在,若存在则插入失败并释放该节点空间。若不存在则通过逐个与树中各节点比较值大小不断向下,得到插入位置,进行节点的插入。

删除节点时先对预删除的节点的值进行查找,若查找失败则删除失败。若查找成功则分为三种情况删除:左右子树均存在、只存在左子树或右子树、叶子结点。后两种情况较为简单不需复杂的变换:叶子结点直接删除,只有一方子树的将子树接到删除节点位置即可。若是左右子树均存在,需找到删除节点左子树中的最大值节点,将此节点接到删除节点的位置,将删除节点的右子树接到此节点的右子树上。

遍历操作采用中序递归遍历和先序递归遍历。

输入/输出设计简要描述:

输入:直接在控制台输入全部整数,两两之间用空格间隔,以0作为结尾代表输入结束。

输出:根据输入操作的不同将不同的结果展示在控制台

编程语言说明:

    使用Visual Studio Code编程。 主要代码采用C语言实现 ;动态存储分配采用C++的new和delete操作符实现;输入与输出采用C++的文件流对象和cout流;程序注释采用C/C++规范。  

主要函数说明:

// 在二叉排序树中查找

BSTNode* SearchBST(BSTree bt, elem key);

// 在二叉排序树中插入

void Insert(BSTree& bt, BSTNode* p, int& count);

// 创建二叉排序树

void CreBst(BSTree& bt);

// 删除二叉排序树中的节点

void erase(BSTree& bt, elem key);

// 中序递归遍历

void Inorder(BSTree T);

// 先序递归遍历

void Preorder(BSTree T);

// 删除功能

void Delete(BSTree& bt);

// 释放二叉排序树空间

void clear(BSTree& bt);

程序测试简要报告:

测试样例(1)

程序输入

二叉排序树示意图

功能测试

结论

程序输出结果与期望输出结果相符。

测试样例(2)

程序输入

二叉排序树示意图

功能测试

结论

程序输出结果与期望输出结果相符。

源程序代码:

#include <iostream>

using namespace std;

// 将int作为元素类型

typedef int elem;

// 自定义二叉排序树节点类型

typedef struct node

{

    elem data;

    // 左子树 右子树

    struct node* lchild, * rchild;

}BSTNode, * BSTree;

// 在二叉排序树中查找

BSTNode* SearchBST(BSTree bt, elem key) {

    // 若bt不为空且bt不是要查找的值

    while (bt && bt->data != key)

    {

        // 如果key比bt小则转到左子树

        if (key < bt->data) {

            bt = bt->lchild;

        }

        else {

            // 否则转到右子树

            bt = bt->rchild;

        }

    }

    // 返回bt 若返回的是NULL则表示未找到

    return bt;

}

// 在二叉排序树中插入

void Insert(BSTree& bt, BSTNode* p, int& count) {

    // bt为二叉排序树 p为要插入的节点 count记录已插入的个数

    // flag为查找p的值是否已在排序二叉树中 若为NULL表示不在可以插入

    BSTNode* flag = SearchBST(bt, p->data);

    if (!flag) {

        // parent为双亲节点

        BSTNode* parent = NULL;

        // pt为插入的位置节点

        BSTNode* pt = bt;

        // 通过p的值不断和二叉排序树中的值不断比较找出pt

        while (pt)

        {

            parent = pt;

            if (p->data < pt->data) {

                pt = pt->lchild;

            }

            else {

                pt = pt->rchild;

            }

        }

        // 如果parent为空表示二叉排序树是空树

        if (parent) {

            // 比parent小则是左子树

            if (p->data < parent->data) {

                parent->lchild = p;

            }

            else {

                // 否则是右子树

                parent->rchild = p;

            }

        }

        else {

            bt = p;

        }

        // 个数加一

        count++;

    }

    else {

        // 如果flag不为空说明p值已在二叉排序树中存在 插入失败

        cout << p->data << "插入失败" << endl;

        delete p;

    }

}

// 创建二叉排序树

void CreBst(BSTree& bt) {

    int value;

    int count = 0;

    cout << "请输入整数: ";

    cin >> value;

    // 如果value不为0 则插入

    while (value != 0)

    {

        // 创建以value为值的节点

        BSTNode* temp = new BSTNode;

        temp->data = value;

        temp->lchild = NULL;

        temp->rchild = NULL;

        // 插入

        Insert(bt, temp, count);

        // 继续读取value

        cin >> value;

    }

    cout << "成功插入 " << count << " 个数" << endl;

}

// 删除二叉排序树中的节点

void erase(BSTree& bt, elem key) {

    // f为p的双亲节点

    BSTNode* f = NULL;

    // p为位置节点

    BSTNode* p = bt;

    // 通过不断比较查找到p

    while (p && key != p->data)

    {

        f = p;

        if (key < p->data) {

            p = p->lchild;

        }

        else {

            p = p->rchild;

        }

    }

    // 如果p为空 说明不存在key值节点 删除失败

    if (!p) {

        cout << "查找失败 删除失败" << endl;

        return;

    }

    // pl为删除节点的左子树

    BSTNode* pl = p->lchild;

    // pr为删除节点的右子树

    BSTNode* pr = p->rchild;

    BSTNode* ps;

    // 替代p节点位置的节点

    BSTNode* s;

    // 如果左右子树都存在 查找左子树中最大值

    if (pl && pr) {

        ps = NULL;

        s = pl;

        while (s->rchild)

        {

            ps = s;

            s = s->rchild;

        }

        if (!ps) {

            pl = s->lchild;

        }

        else {

            ps->rchild = s->lchild;

        }

        s->lchild = pl;

        s->rchild = pr;

    }

    else if (pl) {

        // 只存在左子树

        s = pl;

    }

    else {

        // 只存在右子树

        s = pr;

    }

    // 如果f为空 说明删除根节点

    if (!f) {

        bt = s;

    }

    else if (f->lchild == p) {

        f->lchild = s;

    }

    else {

        f->rchild = s;

    }

    delete p;

    cout << "删除成功" << endl;

}

// 中序递归遍历

void Inorder(BSTree T) {

    /*

        此算法采用递归方式实现中序遍历

    */

    if (T) {

        Inorder(T->lchild);

        cout << T->data << " ";

        Inorder(T->rchild);

    }

}

// 先序递归遍历

void Preorder(BSTree T) {

    /*

        此算法采用递归方式实现先序遍历

    */

    if (T) {

        cout << T->data << " ";

        Preorder(T->lchild);

        Preorder(T->rchild);

    }

}

// 删除功能

void Delete(BSTree& bt) {

    int value;

    cout << "请输入一个整数: ";

    cin >> value;

    erase(bt, value);

}

// 释放二叉排序树空间

void clear(BSTree& bt) {

    if (bt) {

        clear(bt->lchild);

        clear(bt->rchild);

        delete bt;

    }

}

int main(void) {

    // 选项变量

    int choose;

    BSTree bt = NULL;

    // 标志变量 控制循环

    int flag = 1;

    while (flag)

    {

        cout << "------------------------------------------------------" << endl;

        cout << "-      1.插入元素                                    -" << endl;

        cout << "-      2.删除元素                                    -" << endl;

        cout << "-      3.输出                                        -" << endl;

        cout << "-      4.结束程序                                    -" << endl;

        cout << "------------------------------------------------------" << endl;

        cout << "请输入选项: ";

        cin >> choose;

        // 防止选项输入导致出错

        if (cin.fail()) {

            cin.clear();

            cin.ignore(10, '\n');

        }

        switch (choose)

        {

        case 1:

            CreBst(bt);

            system("pause");

            system("cls");

            break;

        case 2:

            if (!bt) {

                cout << "二叉排序树是空树" << endl;

            }

            else {

                Delete(bt);

            }

            system("pause");

            system("cls");

            break;

        case 3:

            cout << "先序顺序: ";

            Preorder(bt);

            cout << "\n中序顺序: ";

            Inorder(bt);

            cout << endl;

            system("pause");

            system("cls");

            break;

        case 4:

            flag = 0;

            clear(bt);

            break;

        default:

            cout << "请输入有效选项!!!" << endl;

            system("pause");

            system("cls");

            break;

        }

    }

    return 0;

}

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

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

相关文章

算法Day30 餐厅的套餐

餐厅的套餐 Description 假设有一家餐厅&#xff0c;菜单上有n道菜可供选择&#xff0c;现在需要从中选择k道菜组成一份套餐。请设计一个算法&#xff0c;返回所有可能但互不相同的菜品组合。 Input 不同菜品的id各不相同&#xff0c;分别为1,2,3…n,输入内容依次为n和k的值&a…

skynet 中 mongo 模块运作的底层原理解析

文章目录 前言总览全流程图涉及模块关系连接数据库函数调用流程图数据库操作函数调用流程图涉及到的代码文件 建立连接SCRAMSASL 操作数据库结语参考链接 前言 这篇文章总结 skynet 中 mongo 的接入流程&#xff0c;代码解析&#xff0c;读完它相信你对 skynet 中的 mongo 调用…

Python:核心知识点整理大全16-笔记

目录 8.2.3 默认值 8.2.4 等效的函数调用 8.2.5 避免实参错误 8.3 返回值 8.3.1 返回简单值 formatted_name.py 8.3.2 让实参变成可选的 8.3.3 返回字典 往期快速传送门&#x1f446;&#xff08;在文章最后&#xff09;&#xff1a; 8.2.3 默认值 编写函数时&#xff…

Docker镜像构建:深入Dockerfile创建自定义镜像

Docker的强大之处在于其能够通过Dockerfile定义和构建自定义镜像&#xff0c;为应用提供独立、可移植的运行环境。在这篇博客文章中&#xff0c;将深入探讨Docker镜像构建的核心概念&#xff0c;通过更加丰富的示例代码&#xff0c;帮助大家全面理解和掌握构建自定义镜像的技术…

机器学习笔记 - 基于C# + .net framework 4.8的ONNX Runtime进行分类推理

该示例是从官方抄的,演示了如何使用 Onnx Runtime C# API 运行预训练的 ResNet50 v2 ONNX 模型。 我这里的环境基于.net framework 4.8的一个winform项目,主要依赖下面版本的相关库。 Microsoft.Bcl.Numerics.8.0.0 Microsoft.ML.OnnxRuntime.Gpu.1.16.3 SixLabors.ImageShar…

掌握iText:轻松处理PDF文档-高级篇-添加水印

前言 iText作为一个功能强大、灵活且广泛应用的PDF处理工具&#xff0c;在实际项目中发挥着重要作用。通过这些文章&#xff0c;读者可以深入了解如何利用iText进行PDF的创建、编辑、加密和提取文本等操作&#xff0c;为日常开发工作提供了宝贵的参考和指导。 掌握iText&…

并发编程-线程等待唤醒机制

目录 前言 ​编辑 线程等待和唤醒的方法 wait() 方法&#xff1a; notify() 方法&#xff1a; 注意事项和建议&#xff1a; 我的其他博客 前言 程等待唤醒机制是多线程编程中用于线程之间协调和通信的一种机制。在多线程环境中&#xff0c;有时候一个线程需要等待某个条件…

【大数据】Doris 架构

Doris 架构 Doris 的架构很简洁&#xff0c;只设 FE&#xff08;Frontend&#xff09;、BE&#xff08;Backend&#xff09;两种角色、两个进程&#xff0c;不依赖于外部组件&#xff0c;方便部署和运维&#xff0c;FE、BE 都可线性扩展。 ✅ Frontend&#xff08;FE&#xff0…

C++_类的定义和使用

目录 1、类的引用 1.1 类的成员函数 1.2 类成员函数的声明和定义 2、类的定义 2.1 类的访问限定&#xff08;封装&#xff09; 3、类重名问题 4、类的实例化 4.1 类的大小 5、隐含的this指针 5.1 空指针问题 结语&#xff1a; 前言&#xff1a; C的类跟c语言中的结…

Standoff 12 网络演习

在 11 月 21 日至 24 日于莫斯科举行的 "Standoff 12 "网络演习中&#xff0c;Positive Technologies 公司再现了其真实基础设施的一部分&#xff0c;包括软件开发、组装和交付的所有流程。安全研究人员能够在安全的环境中测试系统的安全性&#xff0c;并尝试将第三方…

GO闭包实现原理(汇编级讲解)

go语言闭包实现原理(汇编层解析) 1.起因 今天开始学习go语言,在学到go闭包时候,原本以为go闭包的实现方式就是类似于如下cpp lambda value通过值传递,mutable修饰可以让value可以修改,但是地址不可能一样value通过引用传递,但是在其他地方调用时,这个value局部变量早就释放,…

低多边形植物模型法线贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

深度学习在人体动作识别领域的应用:开源工具、数据集资源及趋动云GPU算力不可或缺

人体动作识别检测是一种通过使用计算机视觉和深度学习技术&#xff0c;对人体姿态和动作进行实时监测和分析的技术。该技术旨在从图像或视频中提取有关人体姿态、动作和行为的信息&#xff0c;以便更深入地识别和理解人的活动。 人体动作识别检测的基本步骤包括&#xff1a; 数…

web279(s2-001)

目前java小白一个&#xff0c;主要是学学别人的思路 进入题目&#xff0c;登录框一个 抓包也没发现什么东西 网上说是struts2框架 Struts2是用Java语言编写的一个基于MVC设计模式的Web应用框架 判断是不是基于struts2的一些方法&#xff1a; 1.通过页面回显的错误消息来判断…

MySQL一行记录是怎么存储的?

文章目录 MySQL 一行记录是怎么存储的&#xff1f;MySQL 的数据存放在哪个文件&#xff1f;表空间文件结构 InnoDB行格式有哪些Compact行格式varchar(n) 中 n 最大取值为多少&#xff1f;行溢出后&#xff0c;MySQL是怎么处理的&#xff1f; MySQL 一行记录是怎么存储的&#x…

IDEA 出现问题:git提交commit时Perform code analysis卡住解决方案

问题 git提交commit时Perform code analysis卡住很久 解决方案一 1、打开 IntelliJ IDEA&#xff0c;进入 File -> Settings&#xff08;或者使用快捷键 CtrlAltS&#xff09;。 2、在弹出的 Settings 窗口中&#xff0c;找到 Version Control -> Commit Dialog 选项…

Flink 有状态流式处理

传统批次处理方法 【1】持续收取数据&#xff08;kafka等&#xff09;&#xff0c;以window时间作为划分&#xff0c;划分一个一个的批次档案&#xff08;按照时间或者大小等&#xff09;&#xff1b; 【2】周期性执行批次运算&#xff08;Spark/Stom等&#xff09;&#xff1b…

机器学习---Adaboost算法

1. Adaboost算法介绍 Adaboost是一种迭代算法&#xff0c;其核心思想是针对同一个训练集训练不同的分类器&#xff08;弱分类器&#xff09;&#xff0c;然 后把这些弱分类器集合起来&#xff0c;构成一个更强的最终分类器&#xff08;强分类器&#xff09;。Adaboost算法本身…

CSS学习

CSS学习 1. 什么是css?2.css引入方式2.1 内嵌式2.2 外联式2.3 行内式2.4 引入方式特点 3. 基础选择器3.1 标签选择器3.2 类选择器3.3 id选择器3.4 通配符选择器 1. 什么是css? 2.css引入方式 2.1 内嵌式 2.2 外联式 提示: 需要在html文件中link目标样式表; 2.3 行内式 注意:…

【EventBus】EventBus源码浅析

二、EventBus源码解析 目录 1、EventBus的构造方法2、订阅者注册 2.1 订阅者方法的查找过程2.2 订阅者的注册过程1. subscriptionsByEventType 映射&#xff1a;2. typesBySubscriber 映射&#xff1a;2.3 总结订阅者的注册过程 3、事件的发送 3.1 使用Post提交事件3.2 使用p…