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

news2024/11/24 12:08:04

实验内容及要求: 

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

  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;

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux——基本指令(二)

​ 个人主页&#xff1a;日刷百题 系列专栏&#xff1a;〖C语言小游戏〗〖Linux〗〖数据结构〗 〖C语言〗 &#x1f30e;欢迎各位→点赞&#x1f44d;收藏⭐️留言&#x1f4dd; ​ ​ 写在前面&#xff1a; 紧接上一章&#xff0c;我们在理解接下来的命令之前&#xff0c…

IEEE Transactions on Industrial Electronics工业电子TIE论文投稿须知

一、背景 IEEE TIE作为控制领域的TOP期刊&#xff0c;接收机器人、控制、自动驾驶、仪器和传感等方面的论文&#xff0c;当然范围不止这些&#xff0c;感兴趣的可以自行登录TIE官网查看。所投稿论文必须经过实验验证&#xff0c;偏工程应用类&#xff0c;当然也必须有方法上的…

Qt之自定义QToolTip,去掉显示动画和隐藏延时

一.效果 先来看看Qt原生QToolTip的缺点: 1.当提示内容无变化时,弹窗无法移动。只能先传个空字符串强制弹窗隐藏,然后在新位置再传个字符串。 If the text is the same as the currently shown tooltip, the tip will not move. You can force moving by first hiding the t…

LTspice 中电容的类型

目录 背景钽电容、铝电容陶瓷电容新电容技术聚合物铝电容 背景 在 LTspice 中仿真电路时&#xff0c;需要选择合适的电容&#xff0c;由于刚接触 LTspice 和模拟电路&#xff0c;所以不清楚如何选择与实际常用电容对应的型号&#xff0c;于是整理了一个类型列表&#xff0c;方…

飞天使-linux操作的一些技巧与知识点3-http的工作原理

文章目录 http工作原理nginx的正向代理和反向代理的区别一个小技巧dig 命令巧用 http工作原理 http1.0 协议 使用的是短连接&#xff0c;建立一次tcp连接&#xff0c;发起一次http的请求&#xff0c;结束&#xff0c;tcp断开 http1.1 协议使用的是长连接&#xff0c;建立一次tc…

Ubuntu20.04降低linux版本到5.4.0-26-generic

前言 试用ubuntu20.04安装昇腾的驱动和cann的时&#xff0c;出现如下问题&#xff1a; (base) rootubuntu:/home/work# ./Ascend-hdk-910-npu-driver_23.0.rc3_linux-aarch64.run --full Verifying archive integrity... 100% SHA256 checksums are OK. All good. Uncompr…

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 选项…

Redis - 事务隔离机制

Redis 的事务的本质是 一组命令的批处理 。这组命令在执行过程中会被顺序地、一次性 全部执行完毕&#xff0c;只要没有出现语法错误&#xff0c;这组命令在执行期间是不会被中断。 当事务中的命令出现语法错误时&#xff0c;整个事务在 exec 执行时会被取消。 如果事务中的…

计算机操作系统原理分析期末复习

一、理解与识记 三种基本的OS类型及各自的特点&#xff1a; 批处理系统&#xff08;内存同时存放几个作业。优点&#xff1a;资源利用率高、作业吞吐量大、系统开销小&#xff1b;缺点&#xff1a;用户无交互性、作业平均周转时间长&#xff09;、分时系统&#xff08;时间片技…

排序的简单理解(下)

4.交换排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置 交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 4.1 冒泡排序 冒泡排序&#xff08…

初始数据库 - 了解数据库

centos 7 版本当中安装 mysql 安装与卸载中&#xff0c;⽤⼾全部切换成为root&#xff0c;⼀旦 安装&#xff0c;普通⽤⼾是可以使用的。 卸载不需要的环境 首先&#xff0c;在安装之前&#xff0c;要先确定你当前系统当中是否已经有了mysql 的环境&#xff0c;如果你不想卸…

2023全国职业院校技能大赛信息安全管理与评估正式赛(模块三CTF)

全国职业院校技能大赛高等职业教育组信息安全管理与评估 \任务书\ 模块三 网络安全渗透、理论技能与职业素养 极安云科专注技能竞赛&#xff0c;包含网络建设与运维和信息安全管理与评估两大赛项&#xff0c;及各大CTF&#xff0c;基于两大赛项提供全面的系统性培训&#xf…

用户案例:系统保留分区未分配驱动器号

“遇到了Win7保留分区无法改变驱动器号的问题。我尝试使用激活工具激活Win7时收到提示&#xff0c;系统保留分区未分配驱动器号。根据网上的建议&#xff0c;我打算在磁盘管理中给保留分区分配驱动号。然而&#xff0c;在电脑中我发现了两个未分配驱动器号的分区&#xff0c;一…

【PTA刷题+代码+详解】求二叉树度为1的结点个数(递归法)

文章目录 题目C代码详解 题目 在二叉树T中&#xff0c;其度为1的结点是指某结点只有左孩子或只有右孩子。利用递归方法求二叉树T的度为1的结点个数。 1&#xff09;如果TNULL&#xff0c;则是空树&#xff0c;度为1的结点个数为0&#xff0c;返回值为0&#xff1b; 2&#xff0…

GEE:重分类

作者:CSDN @ _养乐多_ 本文记录了在 Google Earth Engine(GEE)平台上对一副类别图像进行重分类的代码。并以 COPERNICUS/Landcover/100m/Proba-V-C3/Global 数据集中的土地利用数据为例。 结果如下图所示, 文章目录 一、核心函数二、示例代码三、代码链接一、核心函数 核…

保姆级:Windows Server 2012上安装.NET Framework 3.5

目录 一.问题所在无法在安装SQL server2008&#xff08;2012&#xff09; 1.无法安装一下功能 .NET Framework 3.5 二.解决措施 1、打开服务器管理器 2、添加角色和功能 3、选择安装功能 4、指定备用源路径 5、配置本地文件路径 一.问题所在无法在安装SQL server2008&…

【启扬方案】启扬储能管理平板助力储能电站实现智能且高效化运行

在储能领域&#xff0c;储能电站扮演着重要角色&#xff0c;储能电站技术的应用贯穿于电力系统发电、输电、配电、用电的各个环节。实现电力系统削峰填谷、可再生能源发电波动平滑与跟踪计划处理、高效系统调频&#xff0c;增加供电的可靠性。 但随着储能电⼒系统建设发展得越来…

单片机——通信协议(FPGA+c语言应用之iic篇)

一.I2C的功能特点 &#xff08;1&#xff09;功能包括&#xff1a; 1.只需要两条总线&#xff1b; 2.没有严格的波特率要求&#xff0c;例如使用RS232&#xff0c;主设备生成总线时钟&#xff1b; 3.所有组件之间都存在简单的主/从关系&#xff0c;连接到总线的每个设备均可通…

使用Microsoft Dynamics AX 2012 - 9. 核心设置和基本功能

企业的组织结构决定了ERP系统的设置。因此&#xff0c;在开始使用Dynamics AX之前&#xff0c;需要有一个实施项目来设置企业组织和其他核心参数。 实例是Dynamics AX的独立安装&#xff0c;它包含自己的数据库和应用程序。因此&#xff0c;在一个实例中修改配置设置和可编程对…

【Netty的线程模型】

Netty的线程模型 Netty的线程模型知识拓展单Reactor单线程模型单Reactor多线程模型主从Reactor模型 Netty的线程模型 Netty通过Reactor模型基于多路复用器接收并处理用户请求的&#xff0c;多路复用IO模型参考&#xff1a; 多路复用IO模型: 操作系统的IO模型有哪些&#xff1f…