二叉树的实现(递归实现)

前言:本文讲解通过递归的方式实现二叉树的一些基本接口。

目录

通过左右子树的方式实现二叉树:

二叉树的遍历:

 求二叉树结点的个数:

二叉树所有节点的个数:

二叉树叶子节点的个数: 

求第k层节点的节点的个数 :

找二叉树中值为x的节点

求二叉树的高度:

构建二叉树:

销毁二叉树:

重头戏:中序遍历

判断二叉树是否是完全二叉树 


通过左右子树的方式实现二叉树:

结构体的定义:

typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType val;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;

二叉树的遍历:

前序:根 ,左子树, 右子树

中序:左子树 ,根 ,右子树

后序: 左子树, 右子树, 根

根据上图分别走一遍前中后序:

前序:A ,B,NULL,NULL,C,NULL,NULL

中序:NULL,B,NULL,A,NULL,C,NULL

后序:NULL,NULL,B,NULL,NULL,C,A 

想要理解前中后序需要了解递归

每一棵树都可以看成 根   左子树   右子树三部分组成。

代码实现:

//前序遍历
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("null ");return;}printf("%c ", root->val);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);
}

深入理解代码:

以下是上面代码的函数递归调用的代码走读情况。

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("null ");return;}BinaryTreeInOrder(root->left);printf("%d ", root->val);BinaryTreeInOrder(root->right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("null ");return;}BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%d ", root->val);
}

 求二叉树结点的个数:

二叉树所有节点的个数:

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{if (root == NULL)return 0;return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

将问题分解:

如果 root为NULL,返回0;

每个二叉树结点的个数等于左子树节点的个数+右子树节点的个数+根(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);
}

 将问题分解:

如果root为NULL,返回0;

如果左右子树为NULL,该节点为叶子节点就返回1;

二叉树的叶子节点的个数等于左子树叶子节点的个数+右子树叶子节点的个数。

求第k层节点的节点的个数 :

代码:

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root,int k)
{if (root == NULL)return 0;if (k==1)//此时root不等于空return 1;return BinaryTreeLevelKSize(root->left,k-1) + BinaryTreeLevelKSize(root->right,k-1);
}

分解问题:

将问题可以看成: 第K层节点的个数 = 左子树第K-1层节点的个数+右子树K-1层节点的个数

如果root为NULL,返回0;

如果层数为1且该root不为NULL时,返回1


找二叉树中值为x的节点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->val == 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;
}

注意:要创建一个变量接受返回值,然后再返回,如果直接用函数返回返回值,那么就会出现多次重复调用.

分解问题:

找整棵树的问题转化为,找左子树和找右子树的问题

如果root为NULL,返回NULL

如果找到root->val==x,直接返回该节点的地址,

如果左右子树都没有x这个值ULL.

求二叉树的高度:

代码:

//求二叉树的高度
int BinaryTreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftheight = BinaryTreeHeight(root->left);int rightheight = BinaryTreeHeight(root->right);return leftheight > rightheight ? leftheight + 1 : rightheight + 1;
}

 问题分解:

二叉树的高度 = 左右子树中高度最高的高度+1(根)

构建二叉树:

// 通过前序遍历的数组"ABC###D##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType*arr,int* pi)
{if (arr[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));if (root == NULL){perror("malloc fail");return NULL;}root->left = NULL;root->right = NULL;root->val = arr[(*pi)++];root->left = BinaryTreeCreate(arr, pi);root->right = BinaryTreeCreate(arr, pi);return root;
}

‘#’是NULL

疑问:数组下标的指针pi,如果传值的话,就是临时拷贝

如果传的是指针的话,因为是递归,调用递归的被调用的函数中i的改变不会改变调用该函数中的i的值,因为是值拷贝,如果还不理解的话,可以看一下关于函数值调用和址调用的区别。

销毁二叉树:

// 二叉树销毁
void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}

二叉树的销毁采用后续遍历,如果采用前序或后序会非法访问,并且释放不干净。


重头戏:中序遍历

什么是中序遍历?

就是一层一层的遍历。

上图中序遍历的结果是: 1,2,3,4

那么如何实现中序遍历呢?

可以通过队列来实现,现将根节点入队列

每个元素出队列时,打印该节点的值,并将该元素的左右子树的根节点入队列,如果节点为NULL,那么就不入队列,直至队列为空为止

这有一副流程图:

 代码:

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);//初始化队列if(root)QueuePush(&q,root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);//获得队头数据QueuePop(&q);if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);printf("%c ", front->val);}
}

注意:这里队列中的存储的元素的数据类型为,二叉树节点的指针

完成这个代码需要用到以前写过的队列的代码

如果有需要这里有链接,数据结构: 实现初阶数据结构的代码 (gitee.com),如果不会队列的话,也可以看我以前的博客写的队列。

typedef BTNode* QDataType;
typedef struct QNode
{struct QNode* next;QDataType val;
}QNode;

判断二叉树是否是完全二叉树 

这个思路跟上面中序遍历的思路一样,都需要用到队列,不同的是,中序遍历不将NULL入队列,

而这个如果左右子树的根为NULL,仍入队列。 

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front)return false;}return true;
}

思路: 第一次出队列的元素为NULL时,就一直将队列中的元素一直出队列,如果全为NULL则为完全二叉树只要有一个不为NULL,那么就不是完全二叉树。

 

结语:这就是今天的分享,希望看到这篇博客的人都能有所收获。

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

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

相关文章

4,八种GPIO模式

资料来源:【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 仅作个人自学笔记,如有冒犯&#xf…

电子阅览室解决方案

一.方案概述 “电子阅览室”概念一经提出,就得到了广泛的关注,纷纷组织力量进行探讨、研究和开发,进行各种模型的试验。随着数字地球概念、技术、应用领域的发展,电子阅览室已成为数字地球家庭的成员,为信息高速公路提…

uniCloud云存储uni-cdn七牛云扩展存储-开发uniapp项目节约开发成本

为什么要使用uniCloud的扩展存储,那就是省钱,而且DCloud也一直在推uni-cdn,我在项目中也使用七牛云的扩展存储,确实是省钱,如果你的项目使用到大量的图片后者音视频,这些的算计可以帮你省不少钱。下面就通过…

【状态机动态规划】3129. 找出所有稳定的二进制数组 I

本文涉及知识点 动态规划汇总 LeetCode 3129. 找出所有稳定的二进制数组 I 给你 3 个正整数 zero ,one 和 limit 。 一个 二进制数组 arr 如果满足以下条件,那么我们称它是 稳定的 : 0 在 arr 中出现次数 恰好 为 zero 。 1 在 arr 中出现…

dp背包问题

英雄联盟游戏中新出n个英雄,用长度为n的教组 costs 表示每个英雄的定价,其中 costs[i]表示第i个英雄的点券价格。假如你一共有coins点券可以用于消费,且想要买尽可能多的英雄并日选择英雄按costs[i]给出顺序获取。给你价格数组 costs 和金币量…

Golang | Leetcode Golang题解之第116题填充每个节点的下一个右侧节点指针

题目: 题解: func connect(root *Node) *Node {if root nil {return root}// 每次循环从该层的最左侧节点开始for leftmost : root; leftmost.Left ! nil; leftmost leftmost.Left {// 通过 Next 遍历这一层节点,为下一层的节点更新 Next …

vue3 uni-app 中小程序实现 底部tabbar 中间凸起部分 或者说自定义底部tabbar [保姆级别教程]

1、先来看一下效果 2、代码实现 我们还是在 pages.json 中正常配置我们底部的tabbar 但是需要 添加一个字段 "custom": true, //开启自定义tabBar 不填每次原来的tabbar在重新加载时都回闪现 3、 在 pages同一级 或者 里面创建一个 子组件 用来放我们的模版 4、 …

MPLS原理与配置

1.MPLS概述 (1)传统IP路由转发 (2)MPLS基本概念 ⦁ MPLS起源于IPv4(Internet Protocol version 4),其核心技术可扩展到多种网络协议,包括IPv6(Internet Protocol ver…

单片机的内存映射和重映射

内存映射 在单片机内,不管是RAM还是ROM还是寄存器,他们都是真实存在的物理存储器,为了方便操作,单片机会给每一个存储单元分配地址,这就叫做内存映射。 单片机的内存映射是指将外部设备或外部存储器映射到单片…

【软件设计师】——5.数据库系统

目录 5.1 基本概念 5.2 三级模式两级映射 5.3 设计过程和数据模型 5.4 关系代数 5.5 完整性约束 5.6 规范化和反规范化 5.7 控制功能 5.8 SQL语言 5.9 数据库安全 5.10 数据备份 5.11 数据库故障与恢复 5.12 数据仓库、数据挖掘和大数据 5.1 基本概念 相关术语 候选…

三分钟“手撕”顺序表与ArrayList

前言: 实现顺序表的代码放开头,供大家更好的查阅,每个方法都有代码的实现。 其次我会讲解Java自带的ArrayList的实例,扩容机制ArrayList使用方法,遍历以及它的优缺点。 目录 一、自己实现的顺序表 二、Java的ArrayLi…

Python | Leetcode Python题解之第115题不同的子序列

题目&#xff1a; 题解&#xff1a; class Solution:def numDistinct(self, s: str, t: str) -> int:m, n len(s), len(t)if m < n:return 0dp [[0] * (n 1) for _ in range(m 1)]for i in range(m 1):dp[i][n] 1for i in range(m - 1, -1, -1):for j in range(n …

Docker快速安装SQL Server 2022

说明&#xff1a; 系统&#xff1a;Ubuntu 24.04 LTS 拉取SQL Server Docker镜像 docker pull mcr.microsoft.com/mssql/server:2022-CU12-ubuntu-22.04创建数据目录 sudo mkdir /var/mssql_data sudo chmod 777 /var/mssql_data说明&#xff1a; 权限设置为777&#xff0…

ubuntu下vscode的安装包

1.引言 ubuntu下面安装vscode&#xff0c;编码调用接口时可以跳到接口api的位置&#xff0c;因此在ubuntu下安装vscode还是非常有意义的。 2.下载地址 链接&#xff1a;https://pan.baidu.com/s/1j3XNmvbL574p_hYeBqO6dg?pwdryr7 提取码&#xff1a;ryr7 --来自百度网盘超…

如何应对触摸一体机触摸屏失灵问题?怎么校准?

触摸一体机是一种功能强大的设备&#xff0c;集成了电脑、电视和触摸屏等多种功能。其中&#xff0c;触摸屏是其重要组成部分之一。然而&#xff0c;当触摸屏突然失灵时&#xff0c;我们该如何应对呢&#xff1f;以下是一些建议&#xff0c;以帮助您排除问题并重新获得正常触摸…

2024 年你应该选择哪个开源大模型?

自2017年发表的论文《Attention Is All You Need》发明了Transformer架构以来&#xff0c;自然语言处理&#xff08;NLP&#xff09;取得了巨大的进展。随着2022年11月ChatGPT的发布&#xff0c;大型语言模型&#xff08;LLM&#xff09;引起了广泛关注。 你是否想在自己的用例…

通过Zerossl给IP申请免费SSL证书, 实现https ip访问

参考通过Zerossl给IP申请免费SSL证书 | LogDicthttps://www.logdict.com/archives/tong-guo-zerosslgei-ipshen-qing-mian-fei-sslzheng-shu

授权调用: 介绍 Transformers 智能体 2.0

简要概述 我们推出了 Transformers 智能体 2.0&#xff01; ⇒ &#x1f381; 在现有智能体类型的基础上&#xff0c;我们新增了两种能够 根据历史观察解决复杂任务的智能体。 ⇒ &#x1f4a1; 我们致力于让代码 清晰、模块化&#xff0c;并确保最终提示和工具等通用属性透明化…

关于指针和数组的一些经典笔试题解析

前言 大家好&#xff0c;本篇博客将为大家展示一些曾经考过的关于指针的经典笔试题&#xff0c;里面有些题目的难度还是不小的&#xff0c;所以希望大家可以认真理解&#xff1b;如果你点开了本篇博客&#xff0c;麻烦各位大佬一键三连&#xff0c;多多支持&#xff0c;感谢&a…

Aws CodeCommit代码仓储库

1 创建IAM用户 IAM创建admin用户&#xff0c;增加AWSCodeCommitFullAccess权限 2 创建存储库 CodePipeline -> CodeCommit -> 存储库 创建存储库 3 SSH 1) window环境 3.1.1 上载SSH公有秘钥 生成SSH秘钥ID 3.1.2 编辑本地 ~/.ssh 目录中名为“config”的 SSH 配置文…