【数据结构7-2】-二叉排序树(建立、遍历、查找、增加、删除)

目录

  • 1 基础说明
  • 2 基本思路-二叉树的创建和插入
    • 2.1 节点存储结构的建立
    • 2.2 二叉树创建函数的设计
    • 2.3 二叉树插入函数的设计
    • 2.4 简单的进行二叉树的检测看看插入的对不对:
    • 2.5 整体代码:
  • 3 二叉树的遍历
    • 3.1 中序遍历
    • 3.2 程序代码:
    • 3.3 程序结果:
  • 4 二叉树的查找
    • 4.1 改进中序递归查找
    • 4.2 程序结果
  • 5 二叉树节点中序增加

主要是进行代码的书写,原理部分不过多介绍,原理部分应该是优先掌握的,不会原理写代码事倍功半,知道了原理再去理解程序事半功倍

1 基础说明

  在进行二叉树的建立、查找和修改时,要具备一些基本的知识。

  • 首先对于结构体要熟悉,知道结构体的定义和使用,以及结构体常用的别名的使用
  • 其次就是对malloc函数比较熟悉,能熟练的使用malloc进行动态数组的建立
  • 然后就是最重要的就是对链表要很熟悉,至少单链表要能进行建立和查找,删除
  • 然后就是要对二叉树要熟悉,如果二叉树是什么都不知道,怎么进行建立?,要知道其原理,其次要知道二叉树的遍历的三种方式,一般就是有先序、中序、后序,这些遍历的原理至少要掌握
  • 最后就是二叉树的建立要用到一个比较重要的知识点就是递归,其中插入节点要用到地址的递归回溯过程,其他的就跟单链表建立差不多的;

2 基本思路-二叉树的创建和插入

2.1 节点存储结构的建立

  有了上面的基础后,其实内心对于二叉树的建立应该有了一个大致的轮廓,不至于一窍不通,肯定要进行数据的输入,那么就要创建一个能存储数据的结构体:如下

// 创建树的节点结构体
typedef struct tree
{
    int data;
    struct tree *Lchildren;
    struct tree *Rchildren;
    /* data */
} BinTree;

2.2 二叉树创建函数的设计

  有了能存储的结构体,那么下一步就是要创建二叉树,可以分为两个大步骤,第一个就是二叉树的建立,第二个就是进行而叉树的建立;
  第一步进行二叉树的创建函数的设计:这里,先不管插入函数,就先认为已经把插入的功能实现了,进行创建一个二叉树要有一个根节点,这里选用手动进行数据的输入,还要定义一个key,因此每次输入一个数据就要用malloc动态的申请一个节点,(由于这个节点是由malloc函数申请的,数据是放在了堆上,因此这个函数调用完毕,数据也不会清空),并对这个节点进行初始化,然后进行插入,最后执行完这个函数只需要把根节点给返回就行,因此创建函数可以定义为指针函数;

BinTree *CreatNode()
{
    int key;
    BinTree *NewNode;
    BinTree *root = NULL; // 二叉树的根节点,会作为地址返回给主函数
    // 二叉树的根节点,必须设置为空,不然第一次进行插入时,无法正确的插入

    while (1)
    {
        scanf("%d", &key);
        if (key != -1) // 如果key为-1就停止
        {
            NewNode = (BinTree *)malloc(sizeof(BinTree));
            NewNode->data = key;
            NewNode->Lchildren = NULL;
            NewNode->Rchildren = NULL;
            root = InsertTree(root, NewNode); // 调用插入函数
        }
        else
        {
            break;
        }
    }
    return root;
}

2.3 二叉树插入函数的设计

  可以简单考虑一下,对于插入函数要有根节点和新节点的地址,这样方便进行插入,而且每次插入完毕可以把根节点地址给返回回来,这里假设中序插入,思考一下树的定义,以及如何能在我插入完新节点后,地址能一层一层的返回,也就是地址回溯,这样我就递归的寻找到顶点,到顶点后,再依次进行地址回溯,这样就能完成新节点的插入,而对于是中序插入,还是先序插入,完全取决于你写的顺序;插入函数如下:

// 插入函数,递归调用,root是根地址,但是随着递归的调用
//  地址在进行回溯
BinTree *InsertTree(BinTree *root, BinTree *newnode)
{
    if (root == NULL) // 递归的终止条件,终止后把新节点的地址传给上一层,
                      // 上一层继续执行下面的函数(条件都不满足实际上就是直接跳到了return)
                      // ,并把地址传给上上一层,以此类推进行地址的回溯
    {
        root = newnode;
    }
    else
    {
        if (root->data > newnode->data)
        {
            root->Lchildren = InsertTree(root->Lchildren, newnode);
            // 这一点比较难以理解
            // 要理解回溯的思想
        }
        if (root->data < newnode->data)
        {
            root->Rchildren = InsertTree(root->Rchildren, newnode);
        }
    }
    return root;
}

2.4 简单的进行二叉树的检测看看插入的对不对:

  例如插入 7 4 5;如下图:

int main()
{
    BinTree *root;

    root = CreatNode();

    return 0;
}

  输入和打印结果:

2.5 整体代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 创建树的节点结构体
typedef struct tree
{
    int data;
    struct tree *Lchildren;
    struct tree *Rchildren;
    /* data */
} BinTree;

// 插入函数,按照中序插入
BinTree *InsertTree(BinTree *root, BinTree *newnode);
// 二叉树的创建函数
BinTree *CreatNode();

BinTree *CreatNode()
{
    int key;
    BinTree *NewNode;
    BinTree *root = NULL; // 二叉树的根节点,会作为地址返回给主函数
    // 二叉树的根节点,必须设置为空,不然第一次进行插入时,无法正确的插入

    while (1)
    {
        scanf("%d", &key);
        if (key != -1) // 如果key为-1就停止
        {
            NewNode = (BinTree *)malloc(sizeof(BinTree));
            NewNode->data = key;
            NewNode->Lchildren = NULL;
            NewNode->Rchildren = NULL;
            root = InsertTree(root, NewNode); // 调用插入函数
        }
        else
        {
            break;
        }
    }
    return root;
}
// 插入函数,递归调用,root是根地址,但是随着递归的调用
//  地址在进行回溯
BinTree *InsertTree(BinTree *root, BinTree *newnode)
{
    if (root == NULL) // 递归的终止条件,终止后把新节点的地址传给上一层,
                      // 上一层继续执行下面的函数(条件都不满足实际上就是直接跳到了return)
                      // 并把地址传给上上一层,以此类推进行地址的回溯
    {
        root = newnode;
    }
    else
    {
        if (root->data > newnode->data)
        {
            root->Lchildren = InsertTree(root->Lchildren, newnode);
            // 这一点比较难以理解
            // 要理解递归的思想
        }
        if (root->data < newnode->data)
        {
            root->Rchildren = InsertTree(root->Rchildren, newnode);
        }
    }
    return root;// 要理解回溯的思想
}
int main()
{
    BinTree *root;

    root = CreatNode();
    printf("%d,%d,%d", root->data, (root->Lchildren)->data, ((root->Lchildren)->Rchildren)->data);
    return 0;
}

3 二叉树的遍历

3.1 中序遍历

  继续对上述的代码进行补充,即进行中序遍历输出:中序这里采用递归的方法,其实对于先序和中序,后序都可以采用递归的方法,同时也可以采用堆栈的的方法进行遍历,但是这里就先利用递归的方法进行编写:递归中难以理解就是函数的运行过程,具体理解可以参考下图,其中紫色的箭头就是其程序的运行过程: 尤其注意的是到顶点后不会立刻返回上一个节点,而是会进行两次判断后再次进入上一个顶点:

3.2 程序代码:

// 中序递归遍历,可以这个比较难以理解
void InOrder(BinTree *root)
{
    if (root == NULL)
    {
        return;
    }
    InOrder(root->Lchildren);
    printf("%d,", root->data);
    InOrder(root->Rchildren);
}
int main()
{
    BinTree *root, *find;
    int key;
    root = CreatNode();
    printf("%d,%d,%d", root->data, (root->Lchildren)->data, ((root->Lchildren)->Rchildren)->data);
    InOrder(root);//中序遍历
    return 0;
}

3.3 程序结果:

4 二叉树的查找

  上面已经得到二叉树的中序遍历,那么接下来就是对元素进行查找,其中查找可以把中序的函数修改一下,让其每次与目标值的比较,如果掌握了前面的内容,那么查找函数就是比较好写的:

4.1 改进中序递归查找

  由中序遍历改进而来,其他保持不变

// 改进 中序递归查找
BinTree *InOrderSerach(BinTree *root, int val)
{
    if (root == NULL)
    {
        return NULL;
    }
    BinTree *Find = InOrderSerach(root->Lchildren, val);
    if (Find != NULL)
    {
        return Find; // 如果找了值就一直递归返回,直到返回原函数,后面递归就不执行了
    }
    if (root->data == val)
    {
        return root;
    }
    Find = InOrderSerach(root->Rchildren, val);

    return Find; // 这个不能删除,作为最后,同时返回右子树为空的情况函数的返回值
}
int main()
{
    BinTree *root, *find;
    int key;
    root = CreatNode();
    InOrder(root);
    printf("\n");
    while (1)
    {
        if (key != -1)//key==-1结束
        {
            scanf("%d", &key);
            find = InOrderSerach(root, key);
            printf("\nYES:%d\n", find->data);
        }
        else
        {
            break;
        }
    }

    return 0;
}

4.2 程序结果

5 二叉树节点中序增加

  到目前为止,我们从一个结构体起步,进行了了二叉树的建立,中序遍历,中序递归查找,那么接下来就是增删的内容了,上面的内容可以保持不变;简单想一下,对于二叉树的增加,首先就是要用到插入函数,其次就是左右子树的指针指向要改变一下,弄完后要一直递归返回就行了,剩下的不用管了;
  所以主线就是,先找到插入的位置,然后改变指针指向,最后一直return返回就行了;剩下待补充…

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

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

相关文章

RFID技术引领3C手机镜头模组产线智能化转型

RFID技术引领3C手机镜头模组产线智能化转型 应用背景 随着智能手机市场的快速发展与技术创新&#xff0c;手机镜头模组作为影像功能的核心组件&#xff0c;其生产精度、效率及供应链管理的重要性日益凸显。面对复杂多变的市场需求、严格的品质要求以及激烈的市场竞争&#xf…

MySQL数据库总结

作者&#xff1a;爱塔居-CSDN博客 专栏&#xff1a;数据库 目录 前言 一、数据库操作 1.1 创建数据库 1.2 显示当前数据库 1.3 使用数据库 1.4 删除数据库 二、表的操作 2.1 查看表结构 2.2 创建表 2.3 删除表 三、表的增删改查操作&#xff08;CRUD) 3.1 新增 3.…

改ip地址软件手机怎么弄?分享操作指南与注意事项

随着移动互联网的普及&#xff0c;手机已成为我们日常生活中不可或缺的工具。在某些情况下&#xff0c;我们可能需要更改手机的IP地址&#xff0c;以满足特定的网络需求或实现某些功能。然而&#xff0c;对于许多用户来说&#xff0c;如何在手机上更改IP地址可能是一个相对陌生…

clickhouse与oracle传输数据

参考 https://github.com/ClickHouse/clickhouse-jdbc-bridge https://github.com/ClickHouse/clickhouse-jdbc-bridge/blob/master/docker/README.md clickhouse官方提供了一种方式&#xff0c;可以实现clickhouse与oracle之间传输数据&#xff0c;不仅仅是oracle&#xff0…

ShardingSphere 5.x 系列【25】 数据分片原理之 SQL 解析

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 分片执行流程1.1 Simple Push Down1.2 SQL Federation2. SQL 解析2.1 解析…

代码随想录算法训练营DAY38|C++动态规划Part.1|动态规划理论基础、509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯

文章目录 动态规划理论基础什么是动态规划动态规划的解题步骤DP数组以及下标的含义递推公式DP数组初始化DP数组遍历顺序打印DP数组动态规划五部曲 动态规划应该如何debug 509.斐波那契数什么是斐波那契数列动态规划五部曲确定dp数组下标以及含义确定递推公式dp数组如何初始化确…

场景文本检测识别学习 day07(BERT论文精读)

BERT 在CV领域&#xff0c;可以通过训练一个大的CNN模型作为预训练模型&#xff0c;来帮助其他任务提高各自模型的性能&#xff0c;但是在NLP领域&#xff0c;没有这样的模型&#xff0c;而BERT的提出&#xff0c;解决了这个问题BERT和GPT、ELMO的区别&#xff1a; BERT是用来…

翻译《The Old New Thing》 - Why .shared sections are a security hole

Why .shared sections are a security hole - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040804-00/?p38253 Raymond Chen 2004年08月04日 许多人会推荐使用共享数据节作为在应用程序的多个实例之间共享数据的一种方式。这听起来是个好…

走向大规模应用之前,DePIN 如何突破技术、数据与市场之网

近期&#xff0c;随着分布式物理基础设施网络&#xff08;DePIN&#xff09;的快速演变&#xff0c;一个旨在利用区块链技术彻底改造传统基础设施模型的新兴生态系统正在逐渐浮现。2024 年 4 月&#xff0c;以 peaq 为代表的 DePIN 项目成功筹集了 1500 万美元用于生态系统的扩…

通过 API从 0 到 1 构建 本地 GPTs——1.构建Builder‘s Prompt

目的&#xff1a;帮助小白用户生成结构化 prompt 功能清单 搭建本地 gpts 能力&#xff0c;构建本地企业知识库助手Builder’s Prompt -对话引导构建 prompt 示例&#xff0c;生成助手信息function_call的用法prompt 示例 GPTs 的 Create 能力 用于引导用户构建结构化的 pr…

深度学习的瓶颈是什么!

深度学习主要的瓶颈&#xff1a; 数据依赖与标注问题&#xff1a;深度学习模型通常需要大量的标注数据来进行训练。然而&#xff0c;获取大量的标注数据不仅成本高昂&#xff0c;而且在某些领域&#xff08;如医疗、金融等&#xff09;中可能难以获取足够的标注数据。此外&…

python-excel自动化-openpyxl

openpyxl学习笔记 创建或打开表格存储和遍历数据设置单元格风格过滤器和排序更改工作表的背景颜色合并单元格冻结窗口数字格式公式图像图表条形图折线图散点图 创建或打开表格 # 创建 import datetime from openpyxl import Workbook # 实例化 wb Workbook() # 激活 work…

四:物联网ARM开发

一&#xff1a;ARM体系结构概述 1&#xff1a;控制外设led灯还有一些按键这些就要用到gpio&#xff0c;采集传感器的数据需要adc进行转化数据格式&#xff0c;特殊的外设和传感器是通过特殊的协议接口去进行连接的比如一些轴传感器和主控器的连接是通过spi&#xff0c;IIC 控制…

Check the `candidate.safety_ratings` to see if the respoe was blocked.

ValueError&#xff1a;“response.text”快速访问器仅适用于简单&#xff08;单“部分”&#xff09;文本响应。此响应不是简单的文本。请改用“result.parts”访问器或完整的“result.candidates[index].content.parts”查找。期号 #170 谷歌-双子座/生成-人工智能-python Gi…

JavaScript 日期对象

在 JavaScript 中&#xff0c;你可以使用 Date 对象来处理日期和时间。以下是一些常见的 Date 对象的使用方法&#xff1a; 1、创建日期对象&#xff1a; // 创建一个表示当前日期和时间的 Date 对象 let currentDate new Date();// 创建一个特定日期和时间的 Date 对象 let…

GPB | RegVar:基于深度神经网络的非编码区突变功能预测新方法

Genomics, Proteomics & Bioinformatics &#xff08;GPB&#xff09;发表了由军事医学研究院辐射医学研究所张成岗研究员、周钢桥研究员和卢一鸣副研究员团队完成的题为“RegVar: Tissue-specific Prioritization of Noncoding Regulatory Variants”的方法文章。我们的“…

数据结构 - 栈

目录 一. 栈的概念 二. 栈的结构 三. 栈的实现 1. 实现栈的两种方式 链表实现栈 顺序表实现栈 选择依据 栈的创建 栈的初始化 栈的销毁 入栈 出栈 获取栈顶元素 判断栈是否为空 获取栈中有效数据的个数 一. 栈的概念 栈&#xff08;Stack&#xff09;是一种重要…

VScode Failed to parse remote port from server output

在使用VScode 在连接AutoDL 过程中一直连接不上&#xff0c;显示 Failed to parse remote port from server output 在网上查了很多资料&#xff0c;貌似的没啥用。和我有相同 error 的可以尝试修改setting.json 文件。 添加这条命令&#xff08;我的json文件里面没有&#…

共享购:融合社交分享与消费返利的创新电商模式

共享购电商模式是一种独特的商业模式&#xff0c;巧妙地将社交分享与消费返利结合&#xff0c;让消费者在购物的同时&#xff0c;也能通过平台资产奖励实现价值的双重增长。该平台资产体系主要由共享值和共享积分两大要素构成&#xff0c;共同构建了一个充满活力的电商生态系统…

区块链技术与应用学习笔记(8-9节)——北大肖臻课程

目录 8.挖矿 对于全节点和轻节点思考问题&#xff1f; ①全节点在比特币的主要作用&#xff1f; ②挖矿时当监听到别人已经挖出区块并且延申了最长合法链此时应该立刻放弃当前区块在 本地重新组装一个指向最后这个新合法区块的候选区块&#xff0c;重新开始挖矿。节点这么做…