C语言数据结构:什么是树?什么是二叉树?

点击蓝字

079e405e6057f91705ee9d4b887ccbd2.png

关注我们

前言

在之前的数据结构学习中,我们学习了顺序表、链表、栈、队列这几种结构

它们都是用链表或者数组的方式来实现的,主要考察我们对结构体的运用

今天让我们来学习一个新的数据结构,也就是下面这副图里面的树5e52550ce7bf47e1f61768aa069d077b.png

啊不好意思,图拿错了!????

是下面这个才对

b3cf2bc9d43dd3d0c216306e4da08d43.png

1.什么是树?

1.1树的概念

树是一种非线性的数据结构,它是由n个有限节点组成的具有一定层次关系的集合。

把它叫做树是因为它看起来的确像一个树的根部

当然也可以理解为是树干在上,树叶在下的结构

  • 有一个特殊的节点,被称为根节点,也就是树的开头

  • 除了根节点外,其余节点都是,个互不相交的集合。

  • 每一个集合都是一颗与树的结构类似的子树

  • 每一个节点只能有一个前驱,但是可以有很多个后驱 因此,树是递归定义的

3897b9da059f54a183048e90dedccebf.png

树中的子节点不能有交集

  • 上图中的B节点不能有G这个孩子,因为G已经有父母C了

  • 同理,G节点也不能同时拥有两对父母

  • 子节点之间也不能相连,如E和F不能相连

1.2树的相关知识点

c977e02c20f5b49a4864316e5acbf91e.png节点的度:一个节点含有的子树的个数称为该节点的度;如下图:A的度为6

0be0d2c8bac81d02593cd1a18b221d95.png

叶节点或终端节点:度为0的节点称为叶节点;图中B、C、H、I…等节点为叶节点

非终端节点或分支节点:度不为0的节点;如上图中D、E、F、G…等节点为分支节点

简单的说,就是有娃的节点就是分支节点

f5527efb24aee73424d29d7af2a677cf.png

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;如上图,D是H的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;如上图:H是D的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点;如下图:P、Q是兄弟节点

da63509acf8d96ed43ce7b68c3dfa2ad.png

树的度:一棵树中,最大的节点的度称为树的度;示例中树的度为6(即A的度)

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推

树的高度或深度:树中节点的最大层次;示例中树的高度为4

堂兄弟节点:双亲在同一层的节点互为堂兄弟;如下图:H、I互为兄弟节点

4b7102576e4b4fa7cafcd26afc177a6d.png

节点的祖先:从根到该节点所经分支上的所有节点;示例中A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。示例中所有节点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林

多个不相交的树就是森林

dfd70134c24e9dc392c1c92e8cbc23df.png

1.3树的代码表示

表示树的方式有很多种,比如下面这种

#define N 5 //指定树的度为5
struct TreeNode
{int data;struct TreeNode* subs[N];//用指针数组存放孩子节点的指针
};

但这种方法不够优,给大家展示一个用的最广泛的方法——孩子兄弟表示法

typedef int DataType;
struct Node
{struct Node* _firstChild1; // 第一个孩子结点struct Node* _pNextBrother; // 指向其下一个兄弟结点DataType _data; // 结点中的数据域
};

通过这种方法,父亲节点只需要保存它的第一个娃,其他娃就让大娃的兄弟节点来找

也就是家长只用管老大,老大管老二,老二管老三,依次往下……

e58203c7d025977f3fd91a5b77c682f1.png

实际写代码的结构大概是下图这样

13c2db6ccd4cff346dac50e098c08e38.png

2.二叉树

在实际中,二叉树是使用较多的一种树的结构

2.1概念

二叉树是度为2的树,它是一个特殊的树

  • 二叉树不存在度大于2的节点

  • 二叉树是有序树,它的娃(子树)有左右之分,次序不能颠倒

095435820c17f05e3f9a102fd3704de1.png

所以,二叉树都是由下面各类节点组成的树

caaaf739a9bc0096a7dc8ba5dc4e2ab3.png

2.2特殊的二叉树

满二叉树:如果每一个层的节点数都达到最大值,那这个二叉树就是满二叉树。也就是说:满二叉树的层数为k,且节点总数是2k-1

满二叉树的节点数是一个等比数列公式2 0 + 2 1 + 2 2 + . . . + 2 k − 1 = 1 ∗ ( 1 − 2 k ) / ( 1 − 2 ) = 2 k − 1 2^0+2^1+2^2+...+2^{k-1}=1*(1-2^k)/(1-2)=2^k -1 20+21+22+...+2k−1=1∗(1−2k)/(1−2)=2k−1

1cde083fd177eb163212b748bceac62a.png

完全二叉树:完全二叉树是效率很高的数据结构。对于深度为K,有n个节点的二叉树,当且仅当每一个节点都与深度为K的满二叉树中编号从1至n的节点一一对应时,称为完全二叉树。

简单说来,完全二叉树的最后一层不一定满,但必须要从左到右连续

be49faea09e8f82ac6b6f36cfb25c86e.png

满二叉树是一个特殊的完全二叉树

2.3二叉树的性质

  • 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2(i-1)个结点

  • 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2h-1

  • 对任何一棵二叉树, 如果度为0其叶结点个数为n0, 度为2的分支结点个数为n2,则有n0 = n2+1

  • 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1) 。(ps:是log以2为底,n+1为对数)

  • 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:

  1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点

  2. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子

  3. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

659159ca9a6a981ba862660fc9504b87.png

2.4几个选择题

1. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
A 不存在这样的二叉树
B 200  √
C 198
D 199
//叶子节点的数量 总比度为2的节点多12.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
A n    √
B n+1
C n-1
D n/2
//N0+N1+N2=2n
//2N0+N1-1=2n
//N1只有0和1两种可能,因为n为整数,2n为偶数,所以2N0=2n,N0=n3.一棵完全二叉树的节点数位为531个,那么这棵树的高度为( )
A 11
B 10  √
C 8
D 12
//假设高度是h
//完全二叉树节点最多2^h -1
//             最少2^(h-1)-1 +1
//可以通过这两个公式,推断出h=10

3.二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构

3.1顺序存储

顺序结构存储就是使用数组来存储

一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。

现实使用中只有堆才会使用数组来存储

下一篇博客会带大家认识堆这个特殊的树形结构(和内存里面那个堆????没啥关系哈)

2783f0aba27f892db5af85a0fcf090ec.png

看到这张图,你肯定想问,如果用数组结构存储,那还怎么还原出一颗树????呢?

这里我们需要理解物理存储和逻辑结构的关系

二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树

那怎么计算这种情况下的父亲和娃呢?

  • leftchild=parent*2+1

  • rightchild=parent*2+2

  • parent=(child-1)/2

8f7599ec4f157e25fa81497df5ecd415.png

怎么样,是不是忽然感觉妙级了?

3.2链式存储

这就就没啥好说的啦,使用一个简单的二叉链就能构成二叉树

typedef int BTDataType;
// 二叉链
struct BinaryTreeNode
{struct BinTreeNode* _pLeft; // 指向当前节点左孩子struct BinTreeNode* _pRight; // 指向当前节点右孩子BTDataType _data; // 当前节点的值
}

结语

嘿嘿嘿,本篇博客到这里就结束啦!

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

294fa19443fac6b2201dd19c1aa0078c.png

92633f5a4ea6e80e7a940fd000f1ec23.gif

戳“阅读原文”我们一起进步

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

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

相关文章

如何把CPP源程序改写成C语言?

点击蓝字关注我们曾经参与过公司的bpp项目&#xff0c;就是bluetooth print profile。由于使用了hpijs的开源包&#xff0c;但是是C&#xff0b;&#xff0b;的。由于C&#xff0b;&#xff0b;解释器比C语言解释器占用的存储空间要大500k左右。为了节省有限的存储空间&#xf…

9 个很酷的 CMD 命令

点击蓝字关注我们ipconfig功能&#xff1a;查询本机IP地址操作方法&#xff1a;只要在在打开的cmd命令界面中输入“ipconfig”就可以了。msg功能&#xff1a;向对方电脑发送一条文本提示操作方法&#xff1a;首先你要知道对方的IP地址&#xff0c;接下来输入命令“msg /server:…

使用java进行婚礼庆祝_#102030:在30天内运行20 10K,庆祝Java 20年

使用java进行婚礼庆祝1995年5月23日是技术史上的重要时刻。 业界似乎并未意识到当天发布的语言会在未来几年内完全改变技术的格局。 Java将在今年的同一天庆祝20岁生日。 Java 20年&#xff0c;哇&#xff01; 回顾20年前的存储器时代&#xff0c;思考一下Java的发明时间/方式…

这几行 C++ 代码,真的骚!

点击蓝字关注我们事情是这么一回事&#xff1a;国外有个大佬在StackExchange上发起了一个叫做 Tweetable Mathematical Art 的比赛。参赛者需要用C编写代表三原色的RD、GR、BL三个函数&#xff0c;每个函数都不能超过 140 个字符。每个函数都会接到 i 和 j 两个整型参数&#x…

sts集成jboss_JBoss BPM Travel Agency演示与现代BPM数据集成

sts集成jboss不久前&#xff0c;我们启动了一个规模较大的JBoss Travel Agency演示项目&#xff0c;以展示JBoss BPM Suite的一些更有趣的功能。 我们提供了一系列视频 &#xff0c;不仅向您展示了如何安装它&#xff0c;项目中各种规则和流程工件的含义&#xff0c;还向您介绍…

详解C语言的C#数组

点击蓝字关注我们数组是一种存储相同类型元素的固定大小顺序集合。数组用于存储数据集合&#xff0c;但一般会将数组视为存储在连续存储器位置的相同类型的变量的集合。如果要存储表示100名称学生的分数&#xff0c;需要独立地声明100整数变量。例如&#xff1a;number0.number…

oracle的连接函数,Oracle各种连接函数总结

1.前言Oracle可用连接函数会介绍以下几个Oracle列转行函数 Listagg()strcat()wmsys.wm_concat()2.Oracle列转行函数 Listagg()2.1最基础的用法&#xff1a;LISTAGG(XXX,XXX) WITHIN GROUP( ORDER BY XXX)用法就像聚合函数一样&#xff0c;通过Group by语句&#xff0c;把每个Gr…

抽象工厂模式设计模式_21世纪的设计模式:抽象工厂模式

抽象工厂模式设计模式这是我的演讲的第二部分&#xff0c;“ 21世纪的设计模式” 。 此模式在Java代码中到处都有使用&#xff0c;尤其是在更多“企业”代码库中。 它涉及一个接口和一个实现。 该界面如下所示&#xff1a; public interface Bakery {Pastry bakePastry(Toppi…

对 C 语言指针最详尽的讲解

点击蓝字关注我们指针对于C来说太重要。然而&#xff0c;想要全面理解指针&#xff0c;除了要对C语言有熟练的掌握外&#xff0c;还要有计算机硬件以及操作系统等方方面面的基本知识。所以本文尽可能的通过一篇文章完全讲解指针。为什么需要指针&#xff1f;指针解决了一些编程…

app http routes.php,Laravel:我的应用程序没有被路由(Laravel : My app doesn't get routed)

Laravel&#xff1a;我的应用程序没有被路由(Laravel : My app doesnt get routed)我正在运行我的第一个laravel应用程序&#xff0c;在接下来的几个小时中遇到依赖项安装错误。对不起它可能是一个小错误&#xff0c;但似乎我无法找到。图片较暗&#xff0c;电脑坏了。应用程序…

为什么 Android 必须在主线程更新 UI ?

点击蓝字关注我们为什么Android必须在主线程更新UI&#xff1f;站在各位大牛的肩膀上&#xff0c;谢谢&#xff01;正常情况下&#xff0c;Android需要在UI线程更新UI&#xff0c;然鹅&#xff0c;在特殊情况下&#xff0c;子线程也能更新UI不在讨论之列&#xff0c;这篇文章主…

eclipse m2e配置_使用此首选项可加快Eclipse m2e配置

eclipse m2e配置谁不认识他们。 Eclipse中的旧式JFace对话框可以使您直观地看到实际上是一个相当简单的XML或属性文件。 对于m2e&#xff0c;它看起来像这样&#xff1a; 不幸的是&#xff0c;此屏幕的加载速度有点慢&#xff0c;除了检查版本号和其他您将永远不会更改的东西…

学点 STL C++ 的线性容器

点击蓝字关注我们std::array看到这个容器的时候肯定会出现这样的问题&#xff1a;为什么要引入 std::array 而不是直接使用 std::vector&#xff1f;已经有了传统数组&#xff0c;为什么要用 std::array?先回答第一个问题&#xff0c;与 std::vector 不同&#xff0c;std::arr…

C++:良好的编程习惯与编程要点

点击蓝字关注我们以良好的方式编写C class假设现在我们要实现一个复数类complex&#xff0c;在类的实现过程中探索良好的编程习惯。① Header(头文件)中的防卫式声明complex.h: # ifndef __COMPLEX__ # define __COMPLEX__ class complex {} # endif防止头文件的内容被多次包含…

如何使用man命令linux,Linux man命令的使用方法

Linux提供了丰富的帮助手册&#xff0c;当你需要查看某个命令的参数时不必到处上网查找&#xff0c;只要man一下即可。可以使用man man 查看man的使用方法1.man共有以下几个章节代码功能1标准用户命令(Executable programs or shell commands)2系统调用(System calls)functions…

又要卷?挑战 C 语言,新的系统编程语言 Hare 发布

点击蓝字关注我们开发者 Drew DeVault 公布了一门新的系统编程语言 Hare &#xff08;野兔&#xff09;。Hare 的开发时间接近两年半&#xff0c;它使用静态类型系统、手动内存管理和最小运行时&#xff0c;非常适合编写操作系统、系统工具、编译器以及其他低级高性能任务。据 …

java cuba_CUBA平台–新的Java企业应用程序框架

java cuba所以..你好&#xff0c;世界&#xff01; 我们的英语网站终于可以正常使用了&#xff0c;现在每个人都可以下载该平台&#xff0c;并可以以前所未有的速度更快地创建业务应用程序。 在我们决定与国际Java社区共享足够好之前&#xff0c;我们花了六年的永久发展和偶尔的…

进程、线程、协程三个概念傻傻分不清

点击蓝字关注我们进程&#xff0c;是并发执行的程序在执行过程中分配和管理资源的基本单位&#xff0c;每一个进程都有一个自己的地址空间&#xff0c;即进程空间或&#xff08;虚空间&#xff09;。进程空间的大小 只与处理机的位数有关&#xff0c;一个 16 位长处理机的进程空…

C++ STL deque 容器底层实现原理(深度剖析)

点击蓝字关注我们什么是多态&#xff0c;多态有什么用途&#xff1f;定义&#xff1a;“一个接口&#xff0c;多种方法”&#xff0c;程序在运行时才决定调用的函数。实现&#xff1a;C多态性主要是通过虚函数实现的&#xff0c;虚函数允许子类重写override(注意和overload的区…

​常问的16个C语言问题,你能答上来几个?

点击蓝字关注我们最近不少小伙伴在找工作&#xff0c;这里我给大家分享一下面试中经常会遇到的一些嵌入式C语言问题&#xff0c;你看看能答上来几个呢&#xff1f;1用预处理指令#define 声明一个常数&#xff0c;用以表明1年中有多少秒&#xff08;忽略闰年问题&#xff09;#de…