【数据结构】树与二叉树(十六):二叉树的基础操作:插入结点(算法Insert)

news2024/11/20 16:23:41

文章目录

  • 5.2.1 二叉树
    • 二叉树性质
      • 引理5.1:二叉树中层数为i的结点至多有 2 i 2^i 2i个,其中 i ≥ 0 i \geq 0 i0
      • 引理5.2:高度为k的二叉树中至多有 2 k + 1 − 1 2^{k+1}-1 2k+11个结点,其中 k ≥ 0 k \geq 0 k0
      • 引理5.3:设T是由n个结点构成的二叉树,其中叶结点个数为 n 0 n_0 n0,度数为2的结点个数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1
    • 满二叉树、完全二叉树定义、特点及相关证明
  • 5.2.2 二叉树顺序存储
  • 5.2.3 二叉树链接存储
  • 5.2.4 二叉树的遍历
    • 1-3 先序、中序、后序遍历递归实现及相关练习
    • 4. 中序遍历非递归
    • 5. 后序遍历非递归
    • 6. 先序遍历非递归
    • 7. 层次遍历
  • 5.2.5 二叉树的创建
    • 1. 先序创建
    • 2. 复制二叉树
  • 5.2.6 二叉树的基础操作
    • 1. 查找给定结点的父亲
    • 2. 查找结点
    • 3. 插入结点
      • a. 算法InsertLL
      • b. InsertLeft
      • c. InsertRight
      • d. 算法测试
    • 4. 代码整合

5.2.1 二叉树

  二叉树是一种常见的树状数据结构,它由结点的有限集合组成。一个二叉树要么是空集,被称为空二叉树,要么由一个根结点和两棵不相交的子树组成,分别称为左子树右子树。每个结点最多有两个子结点,分别称为左子结点和右子结点。
在这里插入图片描述

二叉树性质

引理5.1:二叉树中层数为i的结点至多有 2 i 2^i 2i个,其中 i ≥ 0 i \geq 0 i0

引理5.2:高度为k的二叉树中至多有 2 k + 1 − 1 2^{k+1}-1 2k+11个结点,其中 k ≥ 0 k \geq 0 k0

引理5.3:设T是由n个结点构成的二叉树,其中叶结点个数为 n 0 n_0 n0,度数为2的结点个数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1

  • 详细证明过程见前文:【数据结构】树与二叉树(三):二叉树的定义、特点、性质及相关证明

满二叉树、完全二叉树定义、特点及相关证明

  • 详细证明过程见前文:【数据结构】树与二叉树(四):满二叉树、完全二叉树及其性质

5.2.2 二叉树顺序存储

  二叉树的顺序存储是指将二叉树中所有结点按层次顺序存放在一块地址连续的存储空间中,详见:
【数据结构】树与二叉树(五):二叉树的顺序存储(初始化,插入结点,获取父节点、左右子节点等)

5.2.3 二叉树链接存储

  二叉树的链接存储系指二叉树诸结点被随机存放在内存空间中,结点之间的关系用指针说明。在链式存储中,每个二叉树结点都包含三个域:数据域(Data)、左指针域(Left)和右指针域(Right),用于存储结点的信息和指向子结点的指针,详见:
【数据结构】树与二叉树(六):二叉树的链式存储

5.2.4 二叉树的遍历

  • 遍历(Traversal)是对二叉树中所有节点按照一定顺序进行访问的过程。
  • 通过遍历,可以访问树中的每个节点,并按照特定的顺序对它们进行处理。
  • 对二叉树的一次完整遍历,可给出树中结点的一种线性排序。
    • 在二叉树中,常用的遍历方式有三种:先序遍历中序遍历后序遍历
    • 这三种遍历方式都可以递归地进行,它们的区别在于节点的访问顺序
      • 在实现遍历算法时,需要考虑递归终止条件和递归调用的顺序。
    • 还可以使用迭代的方式来实现遍历算法,使用栈或队列等数据结构来辅助实现。
  • 遍历是二叉树中基础而重要的操作,它为其他许多操作提供了基础,如搜索、插入、删除等。
    在这里插入图片描述

1-3 先序、中序、后序遍历递归实现及相关练习

【数据结构】树与二叉树(七):二叉树的遍历(先序、中序、后序及其C语言实现)

4. 中序遍历非递归

【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法NIO)

5. 后序遍历非递归

【数据结构】树与二叉树(九):二叉树的后序遍历(非递归算法NPO)

6. 先序遍历非递归

【数据结构】树与二叉树(十):二叉树的先序遍历(非递归算法NPO)

7. 层次遍历

【数据结构】树与二叉树(十一):二叉树的层次遍历(算法LevelOrder)

5.2.5 二叉树的创建

1. 先序创建

  由二叉树的遍历,很容易想到用遍历方法去创建二叉树,我们考虑从先根遍历思想出发来构造二叉树:

【数据结构】树与二叉树(十二):二叉树的递归创建(算法CBT)

2. 复制二叉树

  考虑用后根遍历思想递归复制二叉树的算法CopyTree:

【数据结构】树与二叉树(十三):递归复制二叉树(算法CopyTree)

5.2.6 二叉树的基础操作

1. 查找给定结点的父亲

  • 递归思想
    • 给定结点是指给定的是一个指向某个结点的指针(比如p)。
    • 返回值也应该是指针,指向结点p之父亲的指针(找不到时为空)。

【数据结构】树与二叉树(十四):二叉树的基础操作:查找给定结点的父亲(算法Father )

2. 查找结点

  考虑利用先根遍历在二叉树中搜索符合数据条件(item)的结点p,即满足data§=item的结点。

3. 插入结点

  在二叉树中插入结点,要确定待插入结点与插入位置结点的父子关系。设p为指向待插入结点的指针,简称结点p,s为指向插入位置结点的指针,简称结点s,即要确定p作为s的左儿子还是右儿子,以及如何维护s原来的父子关系。例如,指定p作为s的左儿子,s原来的左儿子作为p的左儿子,则:
在这里插入图片描述

a. 算法InsertLL

Insert

b. InsertLeft

void insertLeft(struct Node* p, struct Node* s) {
    if (s == NULL || p == NULL) {
        return;
    }

    p->left = s->left;

    s->left = p;
}
  • 如果s为空或者p为空,则返回
  • 将p的左儿子设置为s的左儿子
  • 将s的左儿子设置为p

c. InsertRight

void insertRight(struct Node* p, struct Node* s) {
    if (s == NULL || p == NULL) {
        return;
    }

    p->right = s->right;

    s->right = p;
}

  • 如果s为空或者p为空,则返回
  • 将p的右儿子设置为s的右儿子
  • 将s的右儿子设置为p

d. 算法测试

int main() {
    char tostop = '#';
    char input_data[] = {'a', 'b', 'd', '#', '#', 'e', 'f', '#', '#', 'g', '#', '#', 'c', '#', '#'};
    int index = 0;
    
    struct Node* root = CBT(input_data, &index, tostop);
    printf("Inorder Traversal before Insertion: ");
    inorderTraversal(root);
    printf("\n");
    
    struct Node* newNode = createNode('x');
    insertLeft(newNode, root);
    // insertRight(newNode, root);


    printf("Inorder Traversal after Insertion: ");
    inorderTraversal(root);
    printf("\n");

    releaseTree(root);
    root = NULL;

    return 0;
}
  • 采用前文算法CBT,先序递归创建一棵二叉树
  • 创建一个新的结点p,赋值x
  • 在二叉树中插入结点p,作为结点root的左儿子,原左儿子成为p的左儿子
  • 对比插入前后的结果
  • 释放整棵树
    • 注意,需要将释放的指针置为 NULL,以防止悬空指针。

4. 代码整合

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

// 二叉树结点的定义
struct Node {
    char data;
    struct Node* left;
    struct Node* right;
};

// 创建新结点
struct Node* createNode(char data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("Memory allocation failed!\n");
        exit(1);
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

struct Node* CBT(char data[], int* index, char tostop) {
    char ch = data[(*index)++];
    if (ch == tostop) {
        return NULL;
    } else {
        struct Node* t = createNode(ch);
        t->left = CBT(data, index, tostop);
        t->right = CBT(data, index, tostop);
        return t;
    }
}

// 释放以p指向结点为根的树
void releaseTree(struct Node* p) {
    // 如果p为空,则返回
    if (p == NULL) {
        return;
    }

    // 递归释放左子树
    releaseTree(p->left);

    // 递归释放右子树
    releaseTree(p->right);

    // 释放当前节点
    free(p);
}

// 在二叉树中插入结点p,作为结点s的左儿子
void insertLeft(struct Node* p, struct Node* s) {
    // 如果s为空或者p为空,则返回
    if (s == NULL || p == NULL) {
        return;
    }

    // 将p的左儿子设置为s的左儿子
    p->left = s->left;

    // 将s的左儿子设置为p
    s->left = p;
}

// 在二叉树中插入结点p,作为结点s的右儿子
void insertRight(struct Node* p, struct Node* s) {
    // 如果s为空或者p为空,则返回
    if (s == NULL || p == NULL) {
        return;
    }

    // 将p的右儿子设置为s的右儿子
    p->right = s->right;

    // 将s的右儿子设置为p
    s->right = p;
}

void inorderTraversal(struct Node* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%c ", root->data);
        inorderTraversal(root->right);
    }
}

int main() {
    // 创建一棵二叉树
    char tostop = '#';
    char input_data[] = {'a', 'b', 'd', '#', '#', 'e', 'f', '#', '#', 'g', '#', '#', 'c', '#', '#'};
    int index = 0;

    struct Node* root = CBT(input_data, &index, tostop);
    printf("Inorder Traversal before Insertion: ");
    inorderTraversal(root);
    printf("\n");


    // 创建一个新的结点p
    struct Node* newNode = createNode('x');

    // 在二叉树中插入结点p,作为结点root的左儿子,原左儿子成为p的左儿子
    insertLeft(newNode, root);
    // insertRight(newNode, root);

    // 输出结果
    printf("Inorder Traversal after Insertion: ");
    inorderTraversal(root);
    printf("\n");

    // 释放整棵树
    releaseTree(root);
    // 注意,需要将释放的指针置为 NULL,以防止悬空指针。
    root = NULL;

    return 0;
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【计算机网络笔记】CIDR与路由聚合

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

nodejs+express重定向

前言&#xff1a; 本篇代码中需要安装的依赖包包括&#xff1a;request、express 1.常用重定向方法 nodejs中的重定向可以使用.redirect()方法&#xff0c;该方法中可以传两个参数&#xff1a;code和path&#xff0c;code指重定向时&#xff0c;当前访问的这个接口的返回码3…

20.2 设备树中的 platform 驱动编写

一、设备树下的 platform 驱动 platform 驱动框架分为总线、设备和驱动&#xff0c;总线不需要我们去管理&#xff0c;这个是 Linux 内核提供。在有了设备树的前提下&#xff0c;我们只需要实现 platform_driver 即可。 1. 修改 pinctrl-stm32.c 文件 先复习一下 pinctrl 子系…

C 语言多维数组

C 语言多维数组 在本教程中&#xff0c;您将借助示例学习使用多维数组&#xff08;二维和三维数组&#xff09;。 在C语言编程中&#xff0c;您可以创建一个数组数组。这些数组称为多维数组。例如&#xff0c; float x[3][4];这x是二维&#xff08;2d&#xff09;数组。该数…

14——1

这句话的意思是&#xff0c;如图中月份12天数23时&#xff0c;就是1223&#xff1b;当月份9天数2时&#xff0c;就是0902. 可以看到在上面给出的数组元素中&#xff0c;并没有连续挨在一起的2023数字元素——就有人可能输出答案0。 所以这里要看一下—— ——子序列的含义&…

网络运维Day16

文章目录 Docker简介什么是容器命名空间&#xff1a; Docker 的优缺点 Docker安装Docker镜像管理什么是镜像镜像管理 Docker容器管理运行容器容器启动、停止、重启拷贝文件进入容器容器与应用 DockerfileDockerfile 语法案例 总结 Docker简介 什么是容器 容器是用来装东西的&a…

诡异的bug之dlopen

序 本文给大家分享一个比较诡异的bug&#xff0c;是关于dlopen的&#xff0c;我大致罗列了我项目中使用代码方式及结构&#xff0c;更好的复现这个问题&#xff0c;也帮助大家进一步理解dlopen. 问题复现 以下是项目代码的文件结构&#xff1a; # tree . ├── file1 │ …

【大语言模型】Docker部署清华大学ChatGLM3教程

官方地址&#xff1a;https://github.com/THUDM/ChatGLM3 1 将代码保存至本地 方法1&#xff1a; git clone https://github.com/THUDM/ChatGLM3 方法2&#xff1a; https://github.com/THUDM/ChatGLM3/archive/refs/heads/main.zip 2 创建Docker文件 注&#xff1a;请先…

【分布式】CAP理论详解

一、CAP理论概述 在分布式系统中&#xff0c;CAP是指一组原则&#xff0c;它们描述了在网络分区&#xff08;Partition&#xff09;时&#xff0c;分布式系统能够提供的保证。CAP代表Consistency&#xff08;一致性&#xff09;、Availability&#xff08;可用性&#xff09;和…

CSS特效010:文字颜色渐变的流光效果

查看专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS相关的库、…

Python编程-----网络通信

一.统一资源定位器URL 专为标识Internet网上资源位置而设的一种编址方式 ,URL一般由以下几个部分组成&#xff1a; 传输协议://主机IP地址(或域名地址)[:端口号]/资源所在路径和文件名 •传输协议是指访问该资源所使用的访问协议&#xff1b; •主机IP地址&#xff08;或域名…

C/C++轻量级并发TCP服务器框架Zinx-框架开发002: 定义通道抽象类

文章目录 2 类图设计3 时序图数据输入处理&#xff1a;输出数据处理总流程 4 主要实现的功能4.1 kernel类&#xff1a;基于epoll调度所有通道4.2 通道抽象类&#xff1a;4.3 标准输入通道子类4.4 标准输出通道子类4.5 kernel和通道类的调用 5 代码设计5.1 框架头文件5.2 框架实…

MATLAB中Filter Designer的使用以及XILINX Coefficient(.coe)File的导出

文章目录 Filter Designer的打开滤波器参数设置生成matlab代码生成XILINX Coefficient(.COE) File实际浮点数的导出官方使用教程 Filter Designer的打开 打开Filter Designer&#xff1a; 方法一&#xff1a;命令行中输入Filter Designer&#xff0c;再回车打开。 方法二&…

夸克发布自研大模型 加速下一代搜索体验创新

国产大模型阵营再添新锐选手。11月14日&#xff0c;阿里巴巴智能信息事业群发布全栈自研、千亿级参数的夸克大模型&#xff0c;将应用于通用搜索、医疗健康、教育学习、职场办公等众多场景。夸克App将借助自研大模型全面升级&#xff0c;加速迈向年轻人工作、学习、生活的AI助手…

ORACLE数据库实验总集 实验一 Oracle数据库安装与配置

一、实验目的 &#xff08;1&#xff09;掌握 Oracle数据库服务器的安装与配置 &#xff08;2&#xff09;了解如何检查安装后的数据库服务器产品&#xff0c;验证安装是否成功。 &#xff08;3&#xff09;掌握 Oracle数据库服务器安装过程中出现的问题的解决方法。 二、实验…

2023亚太杯数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

【CASS精品教程】打开cass提示base.dcl未找到文件的解决办法

打开cass 7.1时提示base.dcl未找到文件的解决办法。 文章目录 一、问题描述二、解决办法 一、问题描述 系统上安装了cad2006cass7.1&#xff0c;cass软件可以正常打开&#xff0c;但是在使用屏幕菜单绘制地图时&#xff0c;选择一个工具&#xff0c;提示base.dcl未找到文件&am…

详解 KEIL C51 软件的使用·设置工程·编绎与连接程序

详解 KEIL C51 软件的使用建立工程-CSDN博客 2. 设置工程 (1)在图 2-15 的画面中点击 会弹出如图 2-16 的对话框.其中有 10 个选择页.选择“Target” 项,也就是图 2-16 的画面. 图 2-16 在图 2-16 中,箭头所指的是晶振的频率值,默认是所选单片机最高的可用频率值.该设置值与单…

酷柚易汛ERP- 调拨单操作指南

1、应用场景 调拨单可以记录不同仓库之间货物的转移&#xff0c;只能处理同价调拨&#xff0c;调动前后成本不变。 2、主要操作 2.1 新增调拨单 打开【仓库】-【调拨单】新增调拨单 可将商品从一个仓库调入另一个仓库&#xff1b;单据审核后&#xff0c;扣减商品在调出仓库…

qt+opengl 着色器VAO、VBO、EBO(四)

文章目录 一、顶点着色器和片段着色器代码分析1. 着色器12. 顶点着色器2 二、使用步骤1. 使用着色器12. 使用着色器23. 在着色器2中使用EBO 三、完整代码 一、顶点着色器和片段着色器代码分析 1. 着色器1 用到的坐标矩阵, 四个四边形顶点坐标 float vertices_data[36] {// 所…