数据结构之链式二叉树

当我们初步了解二叉树后

我们就可以进一步去深入学习二叉树了

1.链式二叉树的遍历

这里我们先去定义链式二叉树的结构

分为两个指针

一左一右

他们分别指向左子树和右子树

typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinartTreeNode* left;struct BinartTreeNode* right;
}TreeNode;

左右子树的节点又可以细分为:根,左子树,右子树

图中的1节点就是根,2和3则是左子树,456则是右子树

1.1二叉树的前序,中序,后序遍历


前序遍历、中序遍历和后序遍历。这些遍历方式指的是节点访问的顺序。

前序遍历:在前序遍历中,我们首先访问根节点,然后递归地进行左子树的前序遍历,接着递归地进行右子树的前序遍历。


中序遍历:中序遍历中,我们首先递归地进行左子树的中序遍历,然后访问根节点,最后递归地进行右子树的中序遍历。


后序遍历:后序遍历中,我们首先递归地进行左子树的后序遍历,然后递归地进行右子树的后序遍历,最后访问根节点。

而这里呢我们又遇到了老朋友递归

问题不大

我们利用一棵树为例子

图中的这一棵树

以一为根

接下来我们先进行前序遍历

1.1.1前序遍历

前序遍历中先根后左右

●所以我们先去访问根1

●访问完根1后就访问左节点2

●接下来以2为根访问2的左节点3

●然后以3为根访问3的左节点,这是他的左节点为空,所以我们返回也就是开始进行递归

●递归到一后,开始进行访问1的右节点4

●访问到四就以4为根访问4的左节点5

●访问5后发现没有左节点就递归到4访问4的右节点

●访问6时没有左节点右节点就开始递归到4再到1

●最后访问结束

这里呢,我们用N代表空

那么访问完打印后应该是这样的

1 2 3 N N N 4 5 N N 6 N N

1.1.2中序遍历

讨论完前序遍历我们进行中序遍历

中序遍历讲的是先左后根最后右

还是利用这棵树

遍历顺序:

●先是访问左子树,1的左子树是2,2的则是3,3没有了左子树也就是空,返回3,然后在访问3的右子树,空,返回到2

这是返回的应该是

N 3 N

●回到2后访问2的左子树空,所以返回到1

N 3 N 2 N

●回到一就访问1的右子树4,然后到4的左子树5,在访问5的左子树空,这时返回到5

N 3 N 2 N 1 N 5 N

这时会有疑问,为什么没有四,不是先访问到4吗?

这里没有4的原因是,返回到1后应该访问它的右子树,而右子树中还有一个左子树5,所以应该先访问5,这里的5优先访问

●然后返回到4,访问4的右子树6,这里优先访问6的左子树,为空,返回到6,访问右子树,为空

N 3 N 2 N 1 N 5 N 4 N 6 N

1.1.3后序遍历

后序遍历则是先左后右最后根

遍历顺序:

还是以这棵树为例


●先访问1的左子树,到3时,他的左子树为空,右子树为空

N N 3

●返回到2后,右子树为空,访问根2,返回1

N N 3 N 2

●回到一后,访问一的右子树,同时优先访问右子树中的左子树也就是节点五,访问五的左子树,然后是右子树,然后是五

 N N 3 N 2 N N 5

●J返回到五后访问4的右子树6,然后访问6的左子树和右子树

N N 3 N 2 N N 5 N N 6

●访问完6后就返回访问4,然后访问1

N N 3 N 2 N N 5 N N 6 4 1

2.遍历代码的实现

2.1.树的实现

首先我们需要手搓一棵树

定义出来树的结构

并需要创建新的空间,所以这里包装一个函数

typedef struct BinTreeNode
{struct BinTreeNode* left;struct BinTreeNode* right;int val;
}BTNode;
BTNode* BuyBTNode(int val)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->val = val;newnode->left = NULL;newnode->right = NULL;return newnode;
}
// 手搓一棵树
BTNode* CreateTree()
{BTNode* n1 = BuyBTNode(1);BTNode* n2 = BuyBTNode(2);BTNode* n3 = BuyBTNode(3);BTNode* n4 = BuyBTNode(4);BTNode* n5 = BuyBTNode(5);BTNode* n6 = BuyBTNode(6);n1->left = n2;n1->right = n4;n2->left = n3;n4->left = n5;n4->right = n6;return n1;
}

这样就形成了图形中的树

2.2前序遍历代码

前序遍历的话我们需要用到递归

首如果检测到节点为空,这样的话就打印N并返回

如果没有

那么递归继续往下

因为是前序遍历

所以先递归左然后再递归右

void PreOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->val);PreOrder(root->left);PreOrder(root->right);
}

2.3中序遍历代码

中序遍历和前序遍历的不同是前序遍历先根后左右,中序遍历则是先左后根最后右

所以,我们还是先遇到空返回N

没有则是返回左,打印根ra

void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}

2.4后序遍历代码

后序遍历代码则是先左右最后根

所以

void PostOrder(BTNode* root)
{if (root = NULL){printf("N");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->val);
}

2.5测试的结果

3.获取节点个数

获取节点个数,正常情况下我们的思路是定义一个size

然后在遍历的时候进行++size

代码如下

int TreeSize(BTNode* root)
{static int size = 0;if (root == NULL)return 0;else++size;TreeSize(root->left);TreeSize(root->right);return size;
}

但这样会有一个缺点

我们没法去在这个函数里面重置我们的size

所以我们需要再主函数中

每调用完TreeSize函数,就需要重置一遍size

所以我们还有另外一个思路

直接去返回它的左节点和右节点,最后加一

利用递归的思想

代码如下

int TreeSize(BTNode* root)
{return root == NULL ? 0 :TreeSize(root->left) + TreeSize(root->right) + 1;
}

这样就非常巧妙的完成了节点的个数

1.获取叶节点个数
获取叶子结点个数,我们这里也用递归的方法

利用分治思想去解决这个问题

●代码思想:

1. 当遇到空树或者遇到空的节点时,也就是说这是的叶子为NULL,这是我们返回0

2. 当遇到左节点或者右节点为空,当节点不为空时,此时已经到达了叶子结点,所以返回1

3. 当遇到的不是叶节点时,我们需要到递归左节点的个数和右节点的个数,并进行递归返回

●代码思想:

对于整棵树来说,当我们遇到空树或者遇到节点为空的时候,这时的叶子结点为空,我们这时返回0,当不是上中情况的时候,我们从根往下去搜索,先搜索左节点,当左节点不为空,并且左节点的左子树和右子树都是空的时候,这时候就可以确定它是叶子了,也就是返回1,当搜索完左子树就可以搜索右子树,右子树也同理 

4.获取树的高度 

获取树的高度,我们也是利用分治的思想去实现这个代码

首先就是当我们要想返回高度的时候,我们需要调用到左右子树的高度

然后比较左右子树的高度,比较出最大的一个并返回

然后加1(因为我们递归的是左右子树的高度,我们需要整个树的高度,所以还需要加上根,也就是加一)

●代码思想:

1.当我们遇到空树或者遇到的节点为NULL,这时返回0

2.然后接下来去递归左子树和右子树

3.返回时,如果左子树大于右子树,那么就是左子树高度+1,否则右子树高度+1

 

//获取树的高度
int TreeHeight(BTNode* root)
{if (root == NULL){return 0;}TreeHeight(root->left);TreeHeight(root->right);return (TreeHeight(root->left) > TreeHeight(root->right) ? TreeHeight(root->left) : TreeHeight(root->right)) + 1;
}

但这个代码有一定的缺陷

我们可以看到,这个代码我们调用了两次TreeHeight(root->left)和TreeHeight(root->right)

在这一树中,我们调用多次函数,大大增加了计算的难度,在一棵小树中可能不明显,可当树更大时,这时候弊端就先显示出来了

所以我们可以改进一下代码,定义两个变量去接受返回值

然后比较两个返回值

//改进代码
int TreeHeight(BTNode* root)
{if (root == NULL){return 0;}/*TreeHeight(root->left);TreeHeight(root->right);return (TreeHeight(root->left) > TreeHeight(root->right) ? TreeHeight(root->left) : TreeHeight(root->right)) + 1;*/int Heightleft = TreeHeight(root->left);int Heightright = TreeHeight(root->right);return (Heightleft > Heightright ? Heightleft : Heightright + 1);
}

 

5.计算第K层节点个数 

计算k层节点的个数,我们可以看成计算左节点的(k-1)层和右节点(k-1)层的节点个数

因为我们不算顶部节点所以应该是k-1

●代码思想:

首先是如果是空树或者当遇到叶子结点外的空节点时,返回0

当遇到k为1的时候,这时只有一个根,也就返回1

其余情况均利用递归思想,去递归左右子树,注意此时的k应该变成k-1

//计算树k层的节点个数
int TreeKCount(BTNode* root, int k)
{if (root == NULL || k < 1){return 0;}if (k == 1){return 1;}return TreeKCount(root->left, k - 1) + TreeKCount(root->right, k - 1);
}

 

6.寻找某个节点 

寻找某个节点的话,我们也利用递归的方法,分治的思想去解决这个问题

寻找某个节点,那么这个节点如果不在根上,那么就在根的左子树和右子树上

那么就想下寻找

下边的节点也可以分为左子树和右子树和根

依次进行,就形成了递归

//寻找某个节点
BTNode* TreeFind(BTNode* root, int x)
{if (root == NULL){return 0;}if (x == root->val){return root;}TreeFind(root->left, x);TreeFind(root->right, x);return NULL;
}

很多人可能会想到这样的代码

可当我们去运行的时候,我们会发现找不到,不管x为多少都找不到

为什么呢?

原因是我们没有东西去接收

当我们找到的时候,我们递归需要往上递归

可上边的栈中没有可以接受的变量值

所以我们最终遍历完整棵树也找不到我们想找的节点

所以改一下代码

//寻找某个节点
BTNode* TreeFind(BTNode* root, int x)
{if (root == NULL){return 0;}if (x == root->val){return root;}BTNode* ret1 = TreeFind(root->left, x);BTNode* ret2 = TreeFind(root->right, x);if (ret1)return ret1;if (ret2)return ret2;return NULL;
}

 

这样我们利用新建立的节点去接受我们的左右子树的数据

然后如果不为空就不断返回,为空那么就返回0

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

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

相关文章

Django templates 存放html目录

模板 一概述 模板由两部分组成&#xff0c;一部分是HTML代码&#xff0c;一部分是逻辑控制代码&#xff08;变量&#xff0c;标签&#xff0c;过滤器&#xff09; 作用&#xff1a;可以通过一些逻辑控制代码减少一些重复的操作更快速的生成HTML代码&#xff0c;并且实现简单的…

php 对接Mintegral汇量海外广告平台收益接口Reporting API

今天对接的是Mintegral广告reporting api接口&#xff0c;拉取广告收益回来自己做统计。记录分享给大家 首先是文档地址,进入到Mintegral后台就能看到文档地址以及参数&#xff1a; 文档地址&#xff1a;https://cdn-adn-https.rayjump.com/cdn-adn/reporting_api/MintegralRA.…

蓝桥杯刷题(十一)

1.卡片 反向思考&#xff0c;看k种卡片可以分给几位同学 代码 n int(input()) k 1 while k*(k1)<2*n:k1 print(k)2.美丽的2 代码 def f(x)->bool:while x:if x%102:return Truex//10return False cnt 0 for i in range(1,2021):if f(i):cnt1 print(cnt)3.单词分析 …

因聚而生 数智有为丨软通动力携子公司鸿湖万联亮相华为中国合作伙伴大会2024

3月14日&#xff0c;以“因聚而生 数智有为”为主题的“华为中国合作伙伴大会2024”在深圳隆重开幕。作为华为的重要合作伙伴和本次大会钻石级&#xff08;最高级&#xff09;合作伙伴&#xff0c;软通动力深度参与本次盛会&#xff0c;携前沿数智化技术成果和与华为的联合解决…

SpringCloud Bus 消息总线

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第八篇&#xff0c;即介绍 Bus 消息总线。 二、概述 2.1 遗留的问题 在上一篇文章的最后&#xff0c;我…

整型数组按个位值排序 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元素&#xf…

计算机网络——物理层(奈氏准则和香农定理)

计算机网络——物理层&#xff08;奈氏准则和香农定理&#xff09; 失真码间串扰奈氏准则&#xff08;奈奎斯特定理&#xff09;极限数据率 噪声信噪比香农定理奈氏准则和香农定理的区别 前面我们已经了解一些数据通信的基本知识&#xff0c;没有看过上一篇得小伙伴可以点击这里…

网络安全框架和云安全参考架构介绍

目录 一、网络安全框架 1.1 概述 1.2 IATF框架 1.2.1 框架来源 1.2.2 框架结构图 1.2.3 框架内容 1.2.3.1 人&#xff08;People&#xff09; 1.2.3.2 技术&#xff08;Technology&#xff09; 1.2.3.3 操作&#xff08;Operation&#xff09; 1.3 NIST网络安全框架 …

【一】【单片机】有关LED的实验

点亮一个LED灯 根据LED模块原理图&#xff0c;我们可以知道&#xff0c;通过控制P20、P21...P27这八个位置的高低电平&#xff0c;可以实现D1~D8八个LED灯的亮灭。VCC接的是高电平&#xff0c;如果P20接的是低电平&#xff0c;那么D1就可以亮。如果P20接的是高电平&#xff0c;…

stm32-模拟数字转化器ADC

接线图&#xff1a; #include "stm32f10x.h" // Device header//1: 开启RCC时钟&#xff0c;包括ADC和GPIO的时钟//2&#xff1a;配置GPIO将GPIO配置为模拟输入模式//3&#xff1a;配置多路开关将左边的通道接入到规则组中//4&#xff1a;配置ADC转…

JNDI+LDAP攻击手法

服务端&#xff1a; package com.naihe3; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL;import javax.net.ServerSocketFactory; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory;import com.unboundid.…

局部路径规划算法 - 多项式曲线法

参考&#xff1a;局部路径规划算法——曲线插值法 0 前言 1 多项式曲线法 1.1 算法简介 曲线插值的方法是按照车辆在某些特定条件&#xff08;安全、快速、高效&#xff09;下&#xff0c;进行路径的曲线拟合&#xff0c;常见的有多项式曲线、双圆弧段曲线、正弦函数曲线、…

Redis各场景应用集合

应用场景 1、缓存&#xff08;Cache&#xff09;,分布式缓存 有一些存储于数据库中的数据会被频繁访问&#xff0c;如果频繁的访问数据库&#xff0c;数据库负载会升高&#xff0c;同时由于数据库IO比较慢&#xff0c;应用程序的响应会比较差。此时&#xff0c;如果引入Redis来…

CTF题型 SSTI(2) Flask-SSTI典型题巩固

CTF题型 SSTI(2) Flask-SSTI典型题巩固 文章目录 CTF题型 SSTI(2) Flask-SSTI典型题巩固前记1.klf__sstiSSTI_Fuzz字典&#xff08;网上收集自己补充&#xff09; 2.klf_2数字问题如何解决了&#xff1f;|count |length都被禁&#xff1f; 3.klf_3 前记 从基础到自己构造paylo…

手机备忘录怎么导出到电脑,如何将手机备忘录导出到电脑

备忘录是我们日常生活和工作中常用的工具之一&#xff0c;我们可以在手机上轻松地记录重要的事务、想法和灵感。然而&#xff0c;在某些情况下&#xff0c;我们可能需要将手机备忘录导出到电脑进行更详细的整理和管理。那么&#xff0c;手机备忘录怎么导出到电脑&#xff0c;如…

【tls招新web部分题解】

emowebshell (php7.4.21版本漏洞) 非预期 题目提示webshell&#xff0c;就直接尝试一下常见的后门命名的规则 如 shell.php这里运气比较好&#xff0c;可以直接shell.php就出来 要是不想这样尝试的话&#xff0c;也可以直接dirsearch进行目录爆破 然后在phpinfo中直接搜素c…

企业信息安全怎么防护?迅软科技有方法!

一、企业信息防护策略 1、数据加密 使用迅软DSE加密系统&#xff0c;对敏感数据进行加密处理&#xff0c;确保数据在传输和存储过程中的安全性&#xff0c;防止数据泄露。 2、数据备份和恢复 定期备份重要数据&#xff0c;并确保可以在发生灾难性事件后迅速恢复业务运作。 …

力扣大厂热门面试算法题 43-45

43. 字符串相乘&#xff0c;44. 通配符匹配&#xff0c;45. 跳跃游戏 II&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.18 可通过leetcode所有测试用例。 目录 43. 字符串相乘 解题思路 完整代码 Python Java 44. 通配符…

计算机网络的分类

目录 <计算机网络的分类> 1.按网络覆盖范围分 1)个人区域网PAN 2)局域网 3)城域网 4)广域网 5)互联网 2.按传输介质分类 3.按网络传输技术分类 4.按网络的使用性质分类 <计算机网络的分类> 计算机网络分类的方法很多&#xff0c;可以从不同的角度观察网络…

如何使用IDE端通义灵码

如何使用IDE端通义灵码 第一步&#xff1a;安装IDE插件&#xff08; VS Code 和 JetBrains 二选一&#xff09; 如何下载安装VS Code &#xff1a;https://code.visualstudio.com 如何下载安装JetBrains&#xff1a;https://www.jetbrains.com/idea/download 第二步&#x…