初级数据结构(五)——树和二叉树的概念

    文中代码源文件已上传:数据结构源码

 <-上一篇 初级数据结构(四)——队列        |        NULL 下一篇->

1、树结构(Tree)

1.1、树结构的特点

        自然界中的树由根部开始向上生长,随机长出分支,分支之上又可长出分支,层层递进,直至长出叶子则此分支结束。

        数据结构中“树”的概念便是借鉴大自然中的树,将下图垂直镜像翻转便是如此,只是在画结构图时往往更习惯由上向下画。它从根节点开始不断长出分支,直至终端。与自然中的树不同点在于,随着数据后续插入,树结构的叶子节点也可能变为分支节点。

        尤其需要注意,不同分支上的节点不可互相交织,同分支上非父子之间的节点也不可相互交织。所以下图不属于树结构:

        总之,树是若干个节点的有限集,有且仅有一个根节点。树的分支数量可以任意多,也可以不包含分支仅有一个根节点甚至没有节点(没有节点的树称为空树)。不同分支的节点互不相交。

1.2、常用名词

         在了解树结构特点的同时,为了后续使用该结构时方便描述,还应了解几个名词。

        节点( Node ):树中的每一个元素称为节点,上图中每个圆圈都代表一个节点;

        根节点( Root ):最初的节点称为根节点,如上图中的 A ;

        子树( Subtree ):每个节点除开自身,将下一级节点当作新的根节点,从新的根节点往下所有节点的集合称为该节点的子树。上图中 B 及往后的节点是 A 的子树, F 又是 B 的子树(所以树是递归结构);

        分支节点( Branch ):能够延申出其他节点的节点(度不为 0 的节点)都称作分支节点,如上图中红色及蓝色标识的节点都属于分支节点;

        终端节点、叶子节点( Leaf ):不包含任何分支节点的节点(度为 0 的节点)称为终端节点或者叶子节点。上图中绿色标识的节点属于叶子节点;

        度( Degree ):一个节点的分支数量叫作该节点的度,如上图 E 有两个分支 K 和 L ,所以 E 的度是 2 。一棵树中所有节点的度的最大值就是这棵树的度,上图中度最大的节点是 J , 有 4 个度,所以这棵树的度也是 4 ;

        层次( Level ):从树或者子树的顶层到最底层的顺序进行排序。在这个顺序中,每个节点都被视为位于树的某个层次上。最顶上可以视为第 0 层,也可以视作第 1 层。

        深度、高度(Depth):最大层次称为这棵树的深度或者高度。如图中的树从根节点开始向下,最多可经 A、D、J、O、S 这 5 个节点( 5 个层次),所以这棵树的深度为 5 ;

        父节点、双亲节点( Parent ):一个节点的上一级节点称为该节点的父节点或者双亲节点。如图中 E 是 K 的父节点,A 是 B 的父节点;

        子节点( Child ):一个节点的下一级节点称为该节点的子节点。图中的 O、P、Q、R 都是 J 的子节点;

        兄弟节点( Sibling ):与某个节点有同一个父节点的节点称为兄弟节点。如图 E、F 都是 G 的兄弟节点;

        祖先节点( Ancestry ):某个节点上数若干级直到根节点,经过的这些节点都称为祖先节点。图中 A、C、H 都是 M 或者 N 的祖先节点;
        子孙节点( Descendant ):一个节点往下的所有节点都称为该节点的子孙节点。如图中 I、J、O、P、Q、R、S 都是 D 的子孙节点;

        堂兄弟节点( Cousin ):与某个节点同一层次除了自身和兄弟节点外其他所有节点称为该节点的堂兄弟节点。如图中 H、I、J 都是 E、F、G 的堂兄弟节点;

        森林( Forest ):若干颗互不相交的树称为森林。图中剔除 A 节点后, B、C、D 子树则构成森林;

        有序树( Ordered Tree ):一棵树中各子树按照一定规律排序不可互换,则称为有序树。如图中如果将这棵树的 A、B、C …… 当作一种顺序,那么可视为有序树;

        无序树( Unordered Tree ):有序树之外的树都称作无序树。

1.3、树的存储方式

        如上图的树结构,如果要在代码中定义其结构体,常规能想到的是除了定义一个储存数据的成员变量外,定义若干个子节点指针。而由于子节点的数量是不确定的,因此将其定义为数组。

typedef int DATATYPE;
typedef struct Node
{DATATYPE data;            //存储数据size_t childCount;        //子节点个数size_t capacity;          //已开辟空间大小struct Node* child[0];    //子节点指针数组
}Node;

        若要找到图中 1-2-2 节点则执行:

root->child[0]->child[1]->child[1];

        但这对于有序树这种不可随意交换节点位置的结构还好,如果是无序树,而且在经常需要交换节点的情况下, 频繁挪动数组元素显得十分不灵活。因此,还有一种储存方式,每个节点仅储存第一个子节点和其下一个兄弟节点的指针。

        在结构体创建上也显得简单,而且无需每次添加数据都检查空间:

typedef int DATATYPE;
typedef struct Node
{DATATYPE data;struct Node* sibling;struct Node* child;
}Node;

        同样是找到 1-2-2 节点:

root->child->child->sibling->child->sibling;

        看似更为复杂,但整个结构在增删数据或者交换数据的操作上跟之前的结构完全不是一个量级。具体过程这里就不展开赘述,实际上就是对链表和顺序表在增删数据或者交换数据操作上的区别。

2、二叉树( Binary Tree )

2.1、节点基本形态

        二叉树是一种特殊的树,每个节点的子节点不超过 2 个,它的度最大为 2  。此外,二叉树是有序树。一般其节点的结构体类型如下(二叉节点):

typedef int DATATYPE;
typedef struct Node
{DATATYPE data;struct Node* left;struct Node* right;
}

        还有一种三叉节点的结构体定义方式,即将父节点的地址也包含在结构体内:

typedef int DATATYPE;
typedef struct Node
{DATATYPE data;struct Node* parent;struct Node* left;struct Node* right;
}

        不论是二叉节点还是三叉节点,二叉树均只存在以下五种基本形态: 

        其中,由于二叉树是有序树,所以左分支形态和右分支形态不是同一种结构,代码的表现上也完全不同:

//空
root = NULL;
//无分支
root->left = NULL;
root->right = NULL;
//左分支
root->left = &nodeLeft;
root->right = NULL;
//右分支
root->left = NULL;
root->right = &nodeRight;
//双分支
root->left = &nodeLeft;
root->right = &nodeRight;

2.2、二叉树的特殊形态

2.2.1、斜二叉树

        所有节点的左或者右节点全为空的二叉树称为斜二叉树。斜二叉树每一层有且只有一个节点,节点数等于树的深度。如图。

        斜二叉树可看作是一种非环状单链表,使用上也与单链表无差异。

2.2.2、完全二叉树

        如果二叉树的深度为 n ,根节点处于第 0 层,除了最底层节点,其余每一层中第 L 层节点个数 C_{L} 都满足 C_{L} = 2^{L} ,且底层最右侧节点满足其父节点的左子节点不为空,其堂兄弟节点的父节点度都为 2 ,则这类二叉树称为完全二叉树。如下图。

        上面的描述可能有点过于抽象,可以观察图片,然后用另一种方式概括:

                a、完全二叉树的叶子节点仅存在该二叉树的最底层和次底层;

                b、最底层的叶子节点无空隙地紧密排列在左边部分,右边部分可以为空;

                c、次底层的叶子节点无空隙地紧密排列在这一层右侧;

                d、次底层节点的度为 1 时,该节点没有右子节点。

         在同样节点数的二叉树中,不存在其他形态的二叉树深度小于完全二叉树。

2.2.3、满二叉树

        满二叉树是一种特殊的完全二叉树,如图。

        满二叉树的叶子节点只能出现在最下层,每个非叶子节点的分支节点度都为 2 。在所有同深度的二叉树中,满二叉树的节点最多。

2.3、二叉树规律

2.3.1、节点数规律

        二叉树的叶子节点数量总是比度为 2 的节点数多 1 个。

        根据上图可知,叶子节点数量增加总是伴随着度为 2 的节点数增加,而起初只有根节点时,叶子节点数为 1 ,度为 2 的节点数为 0 。因此无论如何增加节点,叶子节点数总是比度为 2 的节点数多 1 个。

2.3.2、完全二叉树标号规律

        将完全二叉树节点如下图从 1 开始自左向右自上向下编号:

         由于整型运算 1 / 2 = 0 ,因此会发现完全二叉树父子间的编号关系如下列代码:

parent = child / 2;
leftChild = parent * 2;
rightChild = parent * 2 + 1;

         而如果从 0 开始编号:

         则满足以下代码:

parent = (child - 1) / 2;
leftChild = parent * 2 + 1;
rightChild = parent * 2 + 2;

        这一特性特别重要,在下一篇关于堆的内容中会用到。

2.3.3、完全二叉树深度

        已知完全二叉树节点数为 n ,其深度为 (int)log_{2}n+1 。

        根据以下代码可以计算出完全二叉树的深度:

#include <math.h>
#include <stdio.h>int main()
{int nodeCount;scanf("%d", &nodeCount);int depth = (int)(log(nodeCount) / log(2)) + 1;printf("Depth = %d\n", depth);return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS Pro SDK文件选择对话框

文件保存对话框 // 获取默认数据库var gdbPath Project.Current.DefaultGeodatabasePath;//设置文件的保存路径SaveItemDialog saveLayerFileDialog new SaveItemDialog(){Title "Save Layer File",OverwritePrompt true,//获取或设置当同名文件已存在时是否出现…

鸿蒙开发编辑器设置

首先需要知道如何打开设置页面&#xff0c;以下所有设置都需要在设置界面中进行修改&#xff0c;有三种方式可以打开&#xff0c; 1、编辑器左上角file菜单下的Setting菜单。 2、编辑器右上角的设置按钮 3、按快捷键 ctrlalts 注意不要和其他软件案件重复。 一、设置每次打开…

Netty常见的设计模式

简介 设计模式在软件开发中起着至关重要的作用&#xff0c;它们是解决常见问题的经过验证的解决方案。而Netty作为一个优秀的网络应用程序框架&#xff0c;同样也采用了许多设计模式来提供高性能和可扩展性。在本文中&#xff0c;我们将探讨Netty中使用的一些关键设计模式&…

记录一次API报文替换点滴

1. 需求 各位盆友在日常开发中&#xff0c;有没有遇到上游接口突然不合作了&#xff0c;临时需要切换其他接口的情况&#xff1f;这不巧了&#xff0c;博主团队近期遇到了&#xff0c;又尴尬又忐忑。 尴尬的是临时通知不合作了&#xff0c;事前没有任何提醒&#xff1b; 忐忑…

CentOS关闭 swap分区

临时关闭swap分区: swapoff -a # 永久关闭swap分区: sed -ri s/.*swap.*/#&/ /etc/fstab 或者 vim /etc/fstab free -m

MyBatis 四大核心组件之 ParameterHandler 源码解析

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

深入理解JVM设计的精髓与独特之处

这是Java代码的执行过程 从软件工程的视角去深入拆解&#xff0c;无疑极具吸引力&#xff1a;首个阶段仅依赖于源高级语言的细微之处&#xff0c;而第二阶段则仅仅专注于目标机器语言的特质。 不可否认&#xff0c;在这两个编译阶段之间的衔接&#xff08;具体指明中间处理步…

Python函数和模块的使用

我的博客 文章首发于公众号&#xff1a;小肖学数据分析 在开发过程中&#xff0c;函数和模块帮助我们将复杂的代码逻辑分解为可管理的部分&#xff0c;提升代码的可读性、可维护性和重用性。 本文将介绍如何在Python中有效利用函数和模块&#xff0c;提供详细的示例。 函数的…

el-date-picker 选择一个或多个日期

el-date-picker可选择多个日期 type“dates” 加个s即可 <div><span>el-date-picker选择多个日期</span><el-date-pickertype"dates"v-model"dateList"placeholder"选择一个或多个日期"></el-date-picker></di…

Graphics Profiler 使用教程

GraphicsProfiler 使用教程 1.工具简介&#xff1a;2.Navigation介绍2.1.打开安装好的Graphics Profiler。2.2.将手机连接到计算机&#xff0c;软件会在手机中安装一个GraphicsProfiler应用(该应用是无界面的&#xff09;。2.3.Show files list2.4.Record new trace2.4.1.Appli…

AcWing 1250. 格子游戏(并查集)

题目链接 活动 - AcWing本课程系统讲解常用算法与数据结构的应用方式与技巧。https://www.acwing.com/problem/content/1252/ 题解 当两个点已经是在同一个连通块中&#xff0c;再连一条边&#xff0c;就围成一个封闭的圈。一般用x * n y的形式将&#xff08;x, y&#xff0…

linux性能优化-上下文切换

如何理解上下文切换 Linux 是一个多任务操作系统&#xff0c;它支持远大于 CPU 数量的任务同时运行&#xff0c;这是通过频繁的上下文切换、将CPU轮流分配给不同任务从而实现的。 CPU 上下文切换&#xff0c;就是先把前一个任务的 CPU 上下文&#xff08;CPU 寄存器和程序计数…

【网络安全技术】电子邮件安全PGP,SMIME

一、PGP&#xff08;Pretty Good Privacy&#xff09; PGP是一种邮件加密手段&#xff0c;他在发邮件一方加密&#xff0c;然后发给发送方邮件服务器&#xff0c;发送方邮件服务器再发送给接收方邮件服务器&#xff0c;然后接收方再从接收方邮件服务器pop出来&#xff0c;这整…

docker-compose单机容器编排

Dockerfile:先配置好文件&#xff0c;然后build&#xff0c;镜像-------->容器。 docker-conpose 既可以基于dockerfile,也可以基于镜像&#xff0c;一键式拉起镜像和容器。 docker-compose核心就是yml文件&#xff0c;可以定义容器的一切。通过yml配置&#xff0c;直接运行…

labelme标注json文件检查标注标签(修改imageWidth,imagePath,imageHeight)

# !/usr/bin/env python # -*- encoding: utf-8 -*- #---wzhimport os import json# 这里写你自己的存放照片和json文件的路径 json_dir =rC:\Users\Lenovo\Desktop\json3 json_files = os.listdir(json_dir

Python+Appium自动化测试之元素等待方法与重新封装元素定位方法

在appium自动化测试脚本运行的过程中&#xff0c;因为网络不稳定、测试机或模拟器卡顿等原因&#xff0c;有时候会出现页面元素加载超时元素定位失败的情况&#xff0c;但实际这又不是bug&#xff0c;只是元素加载较慢&#xff0c;这个时候我们就会使用元素等待的方法来避免这种…

flutter 代码混淆

Flutter 应用混淆&#xff1a; Flutter 应用的混淆非常简单&#xff0c;只需要在构建 release 版应用时结合使用 --obfuscate 和 --split-debug-info 这两个参数即可。 –obfuscate --split-debug-info 用来指定输出调试文件的位置&#xff0c;该命令会生成一个符号映射表。目前…

Idea执行bat使用maven打包springboot项目成docker镜像并push到Harbor

如果执行以下命令失败&#xff0c;先把mvn的-q参数去掉&#xff0c;让错误输出到控制台。 《idea配置优化、Maven配置镜像、并行构建加速打包、解决maven打包时偶尔几个文件没权限的问题》下面的使用company-repo私有仓库和阿里云镜像仓库同时使用的配置参考。 bat echo off …

超详细!大模型面经指南(附答案)

大模型应该算是目前当之无愧的最有影响力的AI技术。它正在革新各个行业&#xff0c;包括自然语言处理、机器翻译、内容创作和客户服务等&#xff0c;成为未来商业环境的重要组成部分。 截至目前大模型已超过100个&#xff0c;大模型纵横的时代&#xff0c;不仅大模型越来越卷&…

DS八大排序之冒泡排序和快速排序

前言 前两期我们已经对"插入排序"&#xff08;直接插入排序和希尔排序&#xff09; 和 "选择排序"&#xff08;直接选择排序和堆排序&#xff09;进行了详细的介绍~&#xff01;这一期我们再来详细介绍一组排序 &#xff1a;"交换排序"即耳熟能…