【数据结构】树与二叉树(五):二叉树的顺序存储(初始化,插入结点,获取父节点、左右子节点等)

news2024/9/30 11:29:23

5.1 树的基本概念

5.1.1 树的定义

  • 一棵树是结点的有限集合T:
    • 若T非空,则:
      • 有一个特别标出的结点,称作该树的,记为root(T);
      • 其余结点分成若干个不相交的非空集合T1, T2, …, Tm (m>0),其中T1, T2, …, Tm又都是树,称作root(T)的子树
    • T 空时为空树,记作root(T)=NULL。

5.1.2 森林的定义

  一个森林是0棵或多棵不相交(非空)树的集合,通常是一个有序的集合。换句话说,森林由多个树组成,这些树之间没有交集,且可以按照一定的次序排列。在森林中,每棵树都是独立的,具有根节点和子树,树与树之间没有直接的连接关系。
  森林是树的扩展概念,它是由多个树组成的集合。在计算机科学中,森林也被广泛应用于数据结构和算法设计中,特别是在图论和网络分析等领域。
在这里插入图片描述

5.1.3 树的术语

  • 父亲(parent)、儿子(child)、兄弟(sibling)、后裔(descendant)、祖先(ancestor)
  • 度(degree)、叶子节点(leaf node)、分支节点(internal node)
  • 结点的层数
  • 路径、路径长度、结点的深度、树的深度

参照前文:【数据结构】树与二叉树(一):树(森林)的基本概念:父亲、儿子、兄弟、后裔、祖先、度、叶子结点、分支结点、结点的层数、路径、路径长度、结点的深度、树的深度

5.1.4 树的表示

  • 【数据结构】树与二叉树(二):树的表示C语言:树形表示法、嵌套集合表示法、嵌套括号表示法 、凹入表示法

5.2 二叉树

5.2.1 二叉树

1. 定义

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

2. 特点

  二叉树的特点是每个结点最多有两个子结点,并且子结点的位置是有序的,即左子结点在前,右子结点在后。这种有序性使得二叉树在搜索、排序等算法中有广泛的应用。

  • 在二叉树中,根结点是整个树的起始点,通过根结点可以访问到整个树的其他结点。每个结点都可以看作是一个独立的二叉树,它的左子树和右子树也是二叉树。

  • 二叉树可以是空树,也可以是只有根结点的树,或者是由多个结点组成的树。每个结点可以包含一个数据元素,以及指向左子结点和右子结点的指针。

  • 二叉树的形状可以各不相同,它可以是平衡的或者不平衡的,具体取决于结点的分布情况。在二叉树中,每个结点的左子树和右子树都是二叉树,因此可以通过递归的方式来处理二叉树的操作。

3. 性质

引理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
  • 详细证明过程见前文:【数据结构】树与二叉树(三):二叉树的定义、特点、性质及相关证明

4. 满二叉树

在这里插入图片描述

  定义5.3:一棵非空高度为 k ( k ≥ 0 ) k( k≥0) k(k0)满二叉树(perfect binary tree),是有 2 k + 1 − 1 2^{k+1}-1 2k+11个结点的二叉树。

5. 完全二叉树

  定义5.4:一棵包含 n n n个节点、高度为 k k k的二叉树 T T T,当按层次顺序编号 T T T的所有节点,对应于一棵高度为 k k k的满二叉树中编号由1至 n n n的那些节点时, T T T被称为完全二叉树(complete binary tree)

  • 满二叉树、完全二叉树性质及证明:【数据结构】树与二叉树(四):满二叉树、完全二叉树及其性质

5.2.2 二叉树顺序存储

  二叉树的顺序存储是指将二叉树中所有结点按层次顺序存放在一块地址连续的存储空间中
  对于完全二叉树,结点的层次顺序反映了其结构,可按层次顺序给出一棵完全二叉树之结点的编号,事实上,这就是完全二叉树的顺序存储方法,结点编号恰好反映了结点间的逻辑关系。
  只要对完全二叉树之结点按照层次顺序进行编号,就可利用一维数组 A A A来存储一棵含有 n n n个结点的完全二叉树,其中A[1]存储二叉树的根结点,A[i]存储二叉树中编号为i的结点,并且结点A[i]的左儿子(若存在)存放在A[2i]处,而A[i]的右儿子(若存在)存放在A[2i+1]处。注意,这里我们约定数组索引从1开始,而不是从0开始,在使用数组存储完全二叉树时,需要留出A[0]位置不使用。

典例

在这里插入图片描述

  首先,我们按照完全二叉树的结点顺序进行编号,从上到下、从左到右依次编号。根据给出的完全二叉树,我们可以得到以下结点编号:

         1
        / \
       2   3
      / \
     4   5

  接下来,我们可以利用一维数组来存储这棵完全二叉树。创建一个大小为6的数组A,其中A[1]表示根结点 A A AA[2]表示结点 B B BA[3]表示结点 E E EA[4]表示结点 C C CA[5]表示结点 D D D

索引:  1   2   3   4   5
数组: [ A,  B,  E,  C,  D ]

  根据完全二叉树的性质,结点 A A A的左儿子应该存放在A[2]的位置,右儿子应该存放在A[3]的位置。结点 B B B的左儿子应该存放在A[4]的位置,右儿子应该存放在A[5]的位置。

例题

  画出下面这棵完全二叉树的顺序存储结构:
在这里插入图片描述
答案见文末 答案见文末 答案见文末

  完全二叉树的顺序存储方式是一种简单且节省空间的存储方式。它只需要使用一个一维数组来存储完全二叉树的结点信息域的值,而不需要额外的空间来存储左儿子和右儿子的地址。

  通过计算结点的编号和数组索引之间的关系,我们可以方便地找到结点的左儿子、右儿子和父亲结点。例如,对于结点i,它的左儿子的编号是2i,右儿子的编号是2i+1,父亲结点的编号是⌊i/2⌋。这种计算关系使得寻找子孙结点和祖先结点变得非常方便和高效。

  顺序存储方式的优点是节省了存储空间,同时访问结点也非常快速,因为可以通过数组索引直接访问结点,而不需要进行指针的跳转。然而,顺序存储方式也有一些限制。由于使用数组存储,需要提前确定完全二叉树的最大结点个数,因此对于结点数不确定或者动态变化的情况下,顺序存储方式可能不适用。

C语言实现

  注意,这里我们约定数组索引从0开始,节点位置计算公式与前文略有不同。

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

#define MAX_SIZE 100  // 定义数组的最大大小

// 二叉树的顺序存储结构
typedef struct {
    char data[MAX_SIZE];  // 数组用于存储结点的数据
    int size;  // 二叉树的大小(结点个数)
} BinaryTree;

// 初始化二叉树
void initBinaryTree(BinaryTree* tree) {
    tree->size = 0;
}

// 向二叉树中插入结点
void insertNode(BinaryTree* tree, int value, int index) {
    if (tree->size >= MAX_SIZE) {
        printf("Binary tree is full. Cannot insert more nodes.\n");
        return;
    }

    if (index < 0 || index > tree->size) {
        printf("Invalid index.\n");
        return;
    }

    // 将插入位置后的结点后移
    for (int i = tree->size - 1; i >= index; i--) {
        tree->data[i + 1] = tree->data[i];
    }

    // 插入新结点
    tree->data[index] = value;
    tree->size++;
}

// 获取结点的父节点编号
int getParentIndex(int index) {
    return (index - 1) / 2;
}

// 获取结点的左子节点编号
int getLeftChildIndex(int index) {
    return 2 * index + 1;
}

// 获取结点的右子节点编号
int getRightChildIndex(int index) {
    return 2 * index + 2;
}

// 根据索引获取结点的值
char getNodeValue(BinaryTree* tree, int index) {
    if (index >= tree->size || index < 0) {
        printf("Invalid index.\n");
        return -1;
    }

    return tree->data[index];
}

int main() {
    BinaryTree tree;
    initBinaryTree(&tree);

    // 向二叉树中插入结点
    insertNode(&tree, 'A', 0);  
    insertNode(&tree, 'B', 1);  
    insertNode(&tree, 'E', 2); 
    insertNode(&tree, 'C', 3); 
    insertNode(&tree, 'D', 4); 

    // 获取结点的值和子节点的值
    char rootValue = getNodeValue(&tree, 0);
    char leftChildValue = getNodeValue(&tree, getLeftChildIndex(0));
    char rightChildValue = getNodeValue(&tree, getRightChildIndex(0));

    printf("Root value: %c\n", rootValue);
    printf("Left child of Root: %c\n", leftChildValue);
    printf("Right child of Root: %c\n", rightChildValue);

    printf("the Parent of B: %c\n", getNodeValue(&tree, getParentIndex(1)));
    printf("the Parent of C: %c\n", getNodeValue(&tree, getParentIndex(3)));
    printf("the Parent of D: %c\n", getNodeValue(&tree, getParentIndex(4)));
    printf("the Parent of E: %c\n", getNodeValue(&tree, getParentIndex(2)));
    return 0;
}

在这里插入图片描述

答案

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

免费好用的网页采集工具软件推荐

在众多各具特色的采集器软件中&#xff0c;真正好用的采集器软件有哪些&#xff1f; 自己一个个去查找和尝试无疑会耗费大量的时间和精力。 因此&#xff0c;在深入体验大多数采集器后&#xff0c;给大家推荐几款优秀且好用的免费网页采集器软件。 本文将对这几款采集器进行…

【机器学习】梯度下降预测波士顿房价

文章目录 前言一、数据集介绍二、预测房价代码1.引入库2.数据3.梯度下降 总结 前言 梯度下降算法学习。 一、数据集介绍 波士顿房价数据集&#xff1a;波士顿房价数据集&#xff0c;用于线性回归预测 二、预测房价代码 1.引入库 from sklearn.linear_model import Linear…

如何处理 java.lang.NoClassDefFoundError

1. 问题背景 系统异常提示java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy 2.问题分析 了解NoClassDefFoundError含义 在开始解决这个问题之前&#xff0c;我们需要先了解一下java.lang.NoClassDefFoundError错误的含义。这个错误通常表示在运行…

借助 DevChat AI 之力,成就我之全栈梦想

何为 DevChat &#xff1f; DevChat 是集好多种 AI 大模型的智能编程工具,可以大大增加我们上班摸鱼的时间。 整合了如 ChatGPT、Codex等热门 AI 模型支持自然语言编程、代码生成与编写、代码补全等功能因其集成热门 AI 智能&#xff0c;相当于站在了巨人的肩膀上&#xff0c…

琛蓝健康明星产品ClamBP™蛤蜊肽,调节血压的针对性方案

琛蓝健康明星产品ClamBP™蛤蜊肽&#xff0c;调节血压的针对性方案 高血压是现今社会最紧迫的公共卫生挑战之一&#xff0c;影响着全球约20%的成人人口。据《中国心血管健康与疾病报告2019》显示&#xff0c;中国高血压患者达2.45亿。长期高血压可引起心脏病、中风、肾功能减退…

Kibana Dashboard饼图展示keyword子字符串去重统计

日志内容 log.info("请求开始 uri: {} header RequestId:{}", request.getRequestURI(), reqId, request.getHeader("request_id"));操作步骤 进入Dashboard菜单 点击Create Dashboard按钮 点击Create Panel按钮 选择Aggregation based 然后选择Pie饼图 …

C#在.NET Windows窗体应用中使用LINQtoSQL

目录 一、新建Windows窗体应用并添加LINQtoSQL类 二、错误信息CS0234 三、添加扩展包让Windows窗体应用支持LINQtoSQL类 默认安装的背景下&#xff0c;新建的Windows窗体应用是不支持LINQtoSQL类的。现象是资源管理器里的依赖项中默认的安装不能自动生成支持system.data.lin…

触摸屏通过modbus转profinet网关连接PLC与变频器485modbus通讯案例

通过兴达易控modbus转profinet网关&#xff08;XD-MDPN100&#xff09;的桥接&#xff0c;数据可以以高速、可靠的方式从触摸屏传递到PLC&#xff0c;同时能够实现PLC对变频器的监控和控制。这四台变频器通过485modbus协议与PLC通讯&#xff0c;使得系统能够实现对变频器的高效…

AI系统源码ChatGPT网站源码+ai绘画系统/支持GPT4.0/支持Midjourney局部编辑重绘

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

信号的阻塞与递达

目录 阻塞信号 信号和相关概念 sigset_t 信号集 信号的保存与阻塞 第一个问题 第二个问题 第三个问题 信号的递达 信号递达 内核态与用户态 为什么可以从用户态到内核态 我们怎么知道现在是内核态还是用户态&#xff1f; 信号的处理 sigaction 可重入函数 vola…

Stable Diffusion源码调试(一)

Stable Diffusion源码调试&#xff08;一&#xff09; 个人模型主页&#xff1a;https://liblib.ai/userpage/369b11c9952245e28ea8d107ed9c2746/model Stable Diffusion版本&#xff1a;https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases/tag/v1.4.1 调试t…

使用 CountDownLatch 实现多线程协作

目录 前言 在多线程编程中&#xff0c;经常需要实现一种机制来协调多个线程的执行&#xff0c;以确保某些操作在所有线程完成后再进行。CountDownLatch 就是 Java 并发包中提供的一种同步工具&#xff0c;它能够让一个或多个线程等待其他线程完成操作。 了解 CountDownLatch …

嵌入式软件工程师面试题——2025校招社招通用(十)

说明&#xff1a; 面试题来源于网络书籍&#xff0c;公司题目以及博主原创或修改&#xff08;题目大部分来源于各种公司&#xff09;&#xff1b;文中很多题目&#xff0c;或许大家直接编译器写完&#xff0c;1分钟就出结果了。但在这里博主希望每一个题目&#xff0c;大家都要…

芯片无线升级,给产品和芯片买个保险

例如&#xff0c;想让卧室灯过于刺眼&#xff0c;需要稍微暗一个度。 目前来说常见的只能重新买了重新安装&#xff1f;&#xff01; 可都已经安装的好的电灯&#xff0c;实在是食之无味&#xff0c;弃之可惜。 这时候产品不拆换&#xff0c;还可以升级就显得尤为重要了。 为了…

React 其他常用Hooks

1. useImperativeHandle 在react中父组件可以通过forwardRef将ref转发到子组件&#xff1b;子组件拿到父组件创建的ref&#xff0c;绑定到自己的某个元素&#xff1b; forwardRef的做法本身没有什么问题&#xff0c;但是我们是将子组件的DOM直接暴露给了父组件&#xff0c;某下…

C++ http协议POST body raw 字段向服务器发送请求

环境&#xff1a;ubuntu系统c使用http协议不是很方便&#xff0c;通过curl库我们可以很方便使用http协议&#xff0c;由于我的请求方式比较特殊&#xff0c;在网上没有找到相关的资料&#xff0c;之前使用python实现过一版&#xff0c;但是当设备数量超过100台时&#xff0c;程…

FPGA时序分析与约束(10)——生成时钟

一、概述 最复杂的设计往往需要多个时钟来完成相应的功能。当设计中存在多个时钟的时候&#xff0c;它们需要相互协作或各司其职。异步时钟是不能共享确定相位关系的时钟信号&#xff0c;当多个时钟域交互时&#xff0c;设计中只有异步时钟很难满足建立和保持要求。我们将在后面…

软件性能测试指标分享,第三方检测机构进行性能测试的好处

在现代科技发展迅猛的时代背景下&#xff0c;软件的性能表现对于用户体验和企业竞争力至关重要。软件性能测试是通过对软件系统进行一系列的测试&#xff0c;以评估其在各种工作条件下的性能表现。这些工作条件可以包括并发用户数、数据量、网络传输速度等。软件性能测试的目的…

[动态规划] (十一) 简单多状态 LeetCode 面试题17.16.按摩师 和 198.打家劫舍

[动态规划] (十一) 简单多状态: LeetCode 面试题17.16.按摩师 和 198.打家劫舍 文章目录 [动态规划] (十一) 简单多状态: LeetCode 面试题17.16.按摩师 和 198.打家劫舍题目分析题目解析状态表示状态转移方程初始化和填表顺序 代码实现按摩师打家劫舍 总结 注&#xff1a;本题与…

python 之 列表推导式

文章目录 基本结构示例 1&#xff1a;将列表中的元素乘以 2 添加条件判断示例 2&#xff1a;筛选出偶数并加倍 嵌套列表推导式示例 3&#xff1a;生成九九乘法表 使用条件表达式示例 4&#xff1a;根据条件返回不同的值 镶嵌使用详细介绍基本结构示例生成二维数组多重筛选和操作…