【数据结构】——链式二叉树

news2024/9/23 10:17:20

目录

一、链式二叉树的定义结构

二、链式二叉树的遍历

2.1前序遍历

2.2中序遍历

2.3后序遍历

2.4层序遍历

三、链式二叉树的基本功能函数

3.1结点个数

3.2叶子结点个数

3.3二叉树第k层结点个数

3.4查找值为x的结点

3.5二叉树的销毁

四、基础OJ

4.1二叉树遍历

4.2左叶子的和

4.3翻转二叉树


一、链式二叉树的定义结构

<1>二叉树的结构体 包含了数据和指向左右子树的指针

typedef int BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;

}BTNode;

<2>二叉树结点的创建

BTNode* BuyNode(BTDataType x)
{
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	root->data = x;
	root->left = NULL;
	root->right = NULL;
	return root;
}

<3>二叉树的创建

BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);

	node1->left = node2;
	node1->right = node4;
	node2->left = node3;
	node4->left = node5;
	node4->right = node6;
	return node1;
}

Tip:二叉树是递归定义的,都可以单独看作 根、左子树、右子树

二、链式二叉树的遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。访问结点所做的操作依赖于具体的应用问题。

遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。

2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。

3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

2.1前序遍历

前序遍历就是按照 根、左子树、右子树的顺序实现遍历

然后左、右子树又按照新的树继续递归下去

值得注意的是不能忘记 3 这个叶子二叉树 它的左子树右子树均为空 但是也是需要访问的

代码实现:

<1>树为空 return结束

<2>树不为空 访问结点,递归左子树、右子树

void PrevOrder(BTNode*root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->data);//根
	PrevOrder(root->left);//左子树
	PrevOrder(root->right);//右子树
}

逻辑分析过程:

逻辑上将一颗树的前序遍历分为 根的访问和左子树的遍历和右子树的遍历。
左右子树的遍历又看成新的一棵树整体的前序遍历。所以我们递归左右子树即可。

物理过程:

函数的调用会创建函数栈帧空间

2.2中序遍历

对比前序遍历 都是整体式的递归访问 但是中序遍历顺序为左子树、根、右子树

代码实现:

void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	InOrder(root->left);//左子树
	printf("%d ", root->data);//根
	InOrder(root->right);//右子树
}

可以看到这里的访问就是打印数据 前序遍历根的访问在前 (因为是 根 左子树 右子树)而中序遍历 先递归到最小的整体单元 (左子树 根 右子树)

2.3后序遍历

与前中序遍历同理,顺序为 左子树 右子树 根

代码实现:

void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	PostOrder(root->left);//左子树
	PostOrder(root->right);//右子树
	printf("%d ", root->data);///根
}

验证一下数据

2.4层序遍历

层序遍历:除了前序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层 上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。


分析:

代码实现:

void TreeLvelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root != NULL)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		//获取队头数据 先进先出 层序遍历
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		printf("%d ", front->data);

		if(front->left)
		QueuePush(&q, front->left);

		if(front->right)
		QueuePush(&q, front->right);

	}
	QueueDestory(&q);
}

BFS:广度优先遍历(层序遍历)

DFS:深度优先遍历(前中后序遍历)

三、链式二叉树的基本功能函数

3.1结点个数

<1>遍历二叉树 size++

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

定义全局静态的size,遍历不为空++,缺点调用必须置零size 过于繁琐

<2>分治递归思想 拆成若干个单元整体

int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) +1;
}

3.2叶子结点个数

叶子结点的特征 左右子树为空 return 1

int BinaryTreeLeafSize(BTNode* root)
{	
	//如果没有这个 会导致空指针的引用报错
	if (root == NULL)
		return 0;
	if (root->left == NULL && root->right== NULL)
		return 1;
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

3.3二叉树第k层结点个数

分析:如何找到返回条件和子问题呢?

int BinaryTreeLevelKSize(BTNode* root, int k)
{
	//返回条件
	if (root == NULL||k==0)
		return 0;
	if (k == 1)
		return 1;

	//子问题
	return BinaryTreeLevelKSize(root->left, k - 1) +BinaryTreeLevelKSize(root->right, k - 1);
}

3.4查找值为x的结点

找到了值为x的结点,需要层层返回给上一层

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	//记录找到的值防止重复调用
	BTNode* ret1 = BinaryTreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = BinaryTreeFind(root->right, x);
	if (ret2)
		return ret2;
	return NULL;
}

递归展开图:

3.5二叉树的销毁

树的销毁也是递归销毁的 仍然是按照 若干个整体单元递归销毁,但是防止找不到左、右子树所以采用后序遍历的思想(左子树 右子树 根)

void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreeDestory(root->left);//左子树的销毁
	BinaryTreeDestory(root->right);//右子树的销毁
	free(root);//根的销毁
}

四、基础OJ

4.1二叉树遍历

二叉树遍历_牛客题霸_牛客网

思路分析:

题目要求我们前序遍历字符串构建一个二叉树,之后中序遍历打印数据

我们按照前序思路遍历 ( 根,左子树,右子树)

<1>遇到 # return NULL

<2>非空 malloc结点记录当前字符 

<3>递归遍历实现

#include <stdio.h>
typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;

}BTNode;
BTNode*CreateTree(char*a,int*pi)
{
    if(a[*pi]=='#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode*root=(BTNode*)malloc(sizeof(BTNode));
    root->data=a[(*pi)++];//访问根
    root->left=CreateTree(a,pi);//构建左子树
    root->right=CreateTree(a, pi);//构建右子树
    return root;
}
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}
int main() {
    char a[100];
    int i=0;
    scanf("%s",a);
    BTNode*root= CreateTree(a, &i);
    InOrder(root);

    return 0;
}

注意:需要同时遍历数组和递归遍历构建二叉树,遍历数组时,如果字符为 # 变量 i 也是需要++的

4.2左叶子的和

. - 力扣(LeetCode)

思路分析:

求的是左子叶的和

<1>保证是左叶子结点

<2>记录左叶子的数值

<3>递归方法返回子树左叶子结点和

int dfs(struct TreeNode* root)
{
    int sum=0;//记录求和数值
    if(root==NULL)
    return 0;
    if(root->left!=NULL)//保证左叶子
    {
        if(root->left->left==NULL&&root->left->right==NULL)//保证叶子结点
        {
            sum+=root->left->val;//加左叶子数值
        }
    }
    //dfs遍历
    sum+=dfs(root->left);//遍历左子树
    sum+=dfs(root->right);//遍历右子树
    return sum;
}

int sumOfLeftLeaves(struct TreeNode* root){
    return dfs(root);
}

4.3翻转二叉树

. - 力扣(LeetCode)

思路分析:

dfs遍历最小的整体单元(根,左子树,右子树)

先叶子结点开始翻转交换,然后左子树,右子树交换

struct TreeNode* invertTree(struct TreeNode* root) {
    if (root == NULL) {
        return NULL;
    }
    struct TreeNode* left = invertTree(root->left);
    struct TreeNode* right = invertTree(root->right);
    root->left = right;
    root->right = left;
    return root;
}

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

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

相关文章

2023-2024年 Java开发岗面试题经验分享

在各行各业中&#xff0c;面试前我们总会思索一个问题&#xff1a;究竟什么样的求职者能获得面试官的青睐&#xff1f;作为求职者&#xff0c;我们又该如何准备&#xff0c;以应对各种面试官的挑战&#xff1f;在这激烈的竞争里&#xff0c;如何才能让自己从众多应聘者中脱颖而…

镭速FTP替代升级页面助力企业创造新创安全运行环境

在当今快速发展的信息技术环境和日益严峻的网络安全挑战下&#xff0c;企业面临着数据传输和文件管理方面的重大挑战。特别是在信创环境下&#xff0c;传统的FTP已逐渐无法满足现代企业的需求&#xff0c;这促使企业寻求更高效、安全的替代方案。 企业在信创环境运行中的挑战 …

(ICLR-2024)PIXART-α:扩散Transformer的快速训练,用于逼真的文本到图像合成

PIXART-α&#xff1a;扩散Transformer的快速训练&#xff0c;用于逼真的文本到图像合成 Paper Title:PIXART-α: FAST TRAINING OF DIFFUSION TRANSFORMER FOR PHOTOREALISTIC TEXT-TO-IMAGE SYNTHESIS Paper是华为诺亚方舟实验室发表在ICLR 2024的工作 Paper地址 Code地址 项…

由浅入深的了解进程(4)

进程 1、优先级1、1、什么是优先级1、2、为什么需要优先级1、3、Linux优先级的特点和查看方式 2、补充概念3、命令行参数4、环境变量 1、优先级 1、1、什么是优先级 和生活中的概念其实是差不多的。优先级在进程中的定义是指定进程获得CPU资源的先后顺序。如果换一个视角的话…

ATF加载自定义镜像

实际上包含了两个问题&#xff1a; 如何把自定义的二进制文件打包到fip.bin中&#xff1f;如何在secure boot流程中load和认证自定义的二进制文件&#xff1f; 如何打包 证书创建工具和FIP打包工具是通过命令行传参的方式进行证书创建和打包的&#xff0c;如下&#xff1a; …

图新地球-新图源来一波(地表覆盖物、地表水、岩土圈)

0.序 以前的GlobalLand30图源不可访问了&#xff0c;很多需要地物分类的朋友很苦恼。 现在星图新上了一批图源&#xff0c;不仅包括地物分类、水域、还包括土壤酸碱度、有机碳、粘土、阳离子等各种岩土相关的地图服务。 这边全部配置成了图新地球可以直接加载的图源&#xff…

人生总会有自认为迈不过去的坎【西藏旅记1】

人生总会有自认为迈不过去的坎 孤独&#xff0c;也是人生一态。 有两个人说过我这样的性格&#xff0c;不会有真正的朋友&#xff0c;一个是旅行时的领队&#xff0c;另一个也是旅行时的领队。 以他们的视角&#xff0c;形形色色的人&#xff0c;应接不暇的景&#xff0c;他们修…

Github 2024-08-01 开源项目日报Top10

根据Github Trendings的统计,今日(2024-08-01统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量非开发语言项目3Go项目2Python项目2C项目1C#项目1Rust项目1TypeScript项目1编程面试大学:成为软件工程师的全面学习计划 创建周期:2859 天协议…

如何基于欧拉系统完成本地软件仓库安装

挂载 [rootlocalhost ~]# mount /dev/sr0/openeuler/ 查看一下 在脚本里添加以下两行 [rootlocalhost ~]# vim /etc/rc.d/rc.local 给一个可执行权限&#xff0c;并重启 [rootlocalhost ~]# chmod x /etc/rc.d/rc.local [rootlocalhost ~]# reboot 记住挂载点 切换到 /et…

CANoe系统变量模块里定义的结构体类型和变量从CAPL代码角度理解

CAPL里声明一个结构体类型&#xff1a; variables {struct DoIPMessage{byte version;byte inVersion;word type;dword length;byte payload[1500];};struct DoIPMessage doipMessage; }声明一个结构体类型DoIPMessage&#xff0c;定义了一个此结构体…

【C语言】C语言期末突击/考研--指针(一篇就够)

目录 一、指针的本质&#xff08;间接访问原理&#xff09; 1.1.指针的定义 1.2.取地址操作符与取值操作符&#xff0c;指针本质 二、指针的传递使用场景 2.1.什么是指针的传递 2.2.指针的传递使用场景 三、指针的偏移使用场景 3.1.指针的偏移 3.2.指针与一维数组 四…

风景视频素材高清无水印的网站有哪些?6个热门素材网站分享

高清无水印风景视频素材网站推荐&#xff0c;让您的视频内容独树一帜&#xff01; 对于视频创作者来说&#xff0c;一段引人入胜的风景视频素材往往能够瞬间抓住观众的注意力&#xff0c;仿佛将他们带入了一个全新的世界。然而&#xff0c;很多创作者在实际拍摄过程中会面临时…

(二)springboot2.7.6集成activit5.23.0之集成设计器

引入官方流程设计器 1. activiti-webapp-explorer2-5.23.0.war项目并解压。 2.将文件夹diagram-viewer和editor-app以及modeler.html拷贝到项目resources/static目录下&#xff1a; 顺便说一下&#xff1a; 在Spring Boot中&#xff0c;静态资源的访问顺序是先找static&#…

QT 安装指南

简介 Qt 是一个跨平台的应用程序开发框架&#xff0c;被广泛应用于桌面、移动设备和嵌入式系统等领域。本文将详细介绍如何在 Windows 操作系统上安装 Qt 5.14.2 版本(这个版本较为稳定适用)。 安装前准备 操作系统: 确保您的计算机运行的是 Windows 10 或更高版本。硬件要求…

【数据结构初阶】二叉树与堆(一)

文章目录 一、树的基础概念1、节点与度数2、树的度与高度3、引入&#xff1a;数组下标为何从0开始4、祖先节点5、树是递归定义的6、树与非树的区别7、代码表示 二、二叉树2.1、满二叉树2.2、完全二叉树2.3、完全二叉树的存储 三、堆 一、树的基础概念 1、节点与度数 节点分为…

app逆向实战之定位关键代码

前言 在保证App能够正常使用的前提下&#xff0c;我们可以通过抓包查看是否存在抓包检测。如果可以进行抓包&#xff0c;我们首先进行登录代码定位&#xff0c;并伪造请求进行登录&#xff0c;然后实现App中的某个功能。本文以某嘟牛app为例&#xff0c;抓包结果如下&#xff…

【投标】运维服务方案(2024Word完整版)

1.项目情况 2.服务简述 2.1服务内容 2.2服务方式 2.3服务要求 2.4服务流程 2.5工作流程 2.6业务关系 2.7培训 3.资源提供 3.1项目组成员 3.2服务保障 软件资料清单列表部分文档&#xff1a; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&a…

vue后台管理系统 vue3+vite+pinia+elementui+axios下

这篇文章来完成用户组件 也就是增删改查表格 用户页面信息页面由头部&#xff0c;表格,和弹框组成 <template><div class"user-header"><el-button type"primary" click"handleAdd">新增</el-button><el-form :inl…

(2024,LlamaGen,Llama,自回归下一token预测,模型扩展)自回归模型优于扩散:Llama 用于可扩展图像生成

Autoregressive Model Beats Diffusion: Llama for Scalable Image Generation 目录 0. 摘要 1. 引言 2. 自回归模型在图像生成中的应用 2.1 概述 2.2 图像 tokenizer 2.3 自回归模型生成图像 2.4 规模扩展 2.5 服务 3. 实验 5. 结论 0. 摘要 我们介绍 LlamaGen&…

使用mid360从0开始搭建实物机器人入门级导航系统,基于Fast_Lio,Move_Base

Introduction 本文原本只是自己在拿到mid360后&#xff0c;开始进行开发过程的一些问题和学习的记录。毕竟实物和仿真还是有很多不同&#xff0c;且由于碰到的问题也比较多&#xff0c;READEME也越来越详细&#xff0c;所以就干脆整合起来&#xff0c;做成了一篇使用mid360的搭…