数据结构(四)——二叉树和堆(下)

制作不易,三连支持一下呗!!!

文章目录

  • 前言
  • 一、叉树链式结构的实现
  • 总结


前言

这篇博客我们将来了解普通二叉树的实现和应用,对大家之前分治和递归的理解有所挑战。


一、二叉树链式结构的实现

1.前置说明

在学习二叉树的基本操作前,需要先创建一棵二叉树,然后才能学习其相关的基本操作,由于我们现在对二叉树结构的掌握还不够深入,此处手动快速创建一棵二叉树,等二叉树结构了解差不多时,再研究二叉树真正的创建方法。

我们已这棵树的结构为例,手动创建一颗二叉树。 

typedef int BTDataType;typedef struct BinTreeNode
{struct BinTreeNode* left;struct BinTreeNode* right;BTDataType val;
}BTNode;BTNode* BuyBTNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("buynode:");return;}newnode->left = newnode->right = NULL;newnode->val = x;return newnode;
}BTNode* CreatTree()
{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.二叉树的遍历

①前序遍历

根左右。前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根节点,然后遍历左子树,最后遍历右子树。
若二叉树为空则结束返回,否则:
(1)访问根结点。
(2)前序遍历左子树。
(3)前序遍历右子树 。
需要注意的是:遍历左右子树时仍然采用前序遍历方法。

根据前序遍历的概念可以看出,前序遍历是递归展开的。我们代码实现时就应该按照分治的思想来书写。

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

在用分治思想解决问题时,我们要抓住这两个重点:

1.想清楚子问题是什么

2..想清楚什么时候是最小子问题。

例如上面二叉树的前序遍历,子问题就是要想遍历这棵树要将它分为根,左子树,右子树。

左子树又分为根,左子树,右子树……依次类推。最小子问题就是当这棵树为空树也就是NULL时,我们逐层返回。

②中序遍历

左根右。中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。

与前序遍历类似,代码实现如下:

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

③后序遍历

左右根。后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。即:
若二叉树为空则结束返回,
否则:
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点

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

④层序遍历 

层序遍历就是一层一层按顺序遍历树,方法就是借助队列的性质,出队列一个就带两个子节点就队列的方法来遍历,直到队列为空,如果出队列的节点为空就不带节点进队列了!!!

void TreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front){printf("%d ", front->val);// 带入下一层QueuePush(&q, front->left);QueuePush(&q, front->right);}else{printf("N ");}}printf("\n");QueueDestroy(&q);
}

3.求二叉树的节点数 

这里我们要写一个求给定二叉树有多少节点的接口

我们还是采用分治的思想,要求一颗二叉树有多少节点还是将它分为左子树和右子树,先求出左右子树有多少节点,最后再加上根节点这一个就可以了。最小子问题还是遇到空树就返回0个节点。

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

4.求二叉树的深度 

我们还是采用分治的思想,要求一颗二叉树的深度还是将它分为左子树和右子树,先求出左右子树的深度中的最大值,再加上根节点的1。最小子问题还是遇到空树就返回0。

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

这里有一个注意点:

可能有些同学会试图将代码简化,不创建leftdepth和rightdepth两个变量,直接返回

 

单从结果上来看,这样写是没有什么问题的。问题出在这样写会使时间复杂度暴增。

之前时间复杂度是O(N),但现在时间复杂度甚至接近2^N。

在leetcode上有一道求二叉树深度题目,如果用改动之后的代码提交上无法通过的,因为效率太低了。

. - 力扣(LeetCode)

5.求第K层节点个数

分治思想:要求第K层节点个数可将问题拆分为求左子树的第K-1层的节点个数和右子树的第K-1层节点个数之后,依此类推。

最小子问题①非空且K==1时就返回1,

②如果根已经为空就返回0。

int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (NULL == root)return 0;if (k == 1)return 1;//如果不为空且k不等于1,就说明第k层在子树中,转换为子问题求解return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}

6.查找值为x的节点的位置 

分治思想:子问题是在左子树找和在右子树找

最小子问题是:如果根为空就返回空,如果根不为空且val==x就返回root

BTNode* TreeFind(BTNode* root, int x)
{if (root == NULL)return NULL;if (root->val == x)return root;BTNode* ret1 = TreeFind(root->left, x);if (ret1)return ret1;return  TreeFind(root->right, x);
}

7. 二叉树的创建和销毁

1.创建

二叉树的创建要依靠前序遍历的结果或中序遍历的结果或后序遍历的结果来构建,后面我们有相关题目,这里不多赘述。

2.销毁

void TreeDestroy(BTNode* root)
{if (root == NULL)return;TreeDestroy(root->left);TreeDestroy(root->right);free(root);root = NULL;
}

总结

我们详细了解了二叉树的存储结构,并初步领会了分治思想

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

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

相关文章

Java入门——继承和多态(上)

包 包是组织类的一种方式. 使用包的主要目的是保证类的唯一性. 例如, 你在代码中写了一个 Test 类. 然后你的舍友也可能写一个 Test 类. 如果出现两个同名的类, 就会冲突, 导致 代码不能编译通过. 导入包中的类 Java 中已经提供了很多现成的类供我们使用. 例如 public cla…

服装店会员管理系统结合小程序商城帮你挖掘出潜在客户

在现代社会,随着科技的不断进步和人们消费习惯的变化,传统的服装店已经不再能够满足消费者的需求。为了更好地服务客户,提升销售业绩,许多服装店开始引入会员管理系统,并结合小程序商城,实现线上线下的无缝…

LeetCode-2079. 给植物浇水【数组 模拟】

LeetCode-2079. 给植物浇水【数组 模拟】 题目描述:解题思路一:简单的模拟题,初始化为0,考虑先不浇灌每一个植物解题思路二:初始化为n,考虑每一个植物需要浇灌解题思路三:0 题目描述&#xff1a…

C++11:常用语法汇总

目录 🍁统一的列表初始化 { }initializer_list 🍁decltype 推导表达式类型🍁可变参数模板解析可变参数包方法一方法二 🍁lambda 表达式捕捉列表的使用运用场景举例lambda表达式 与 函数对象 🍁统一的列表初始化 { } 在…

STM32F407-驱动SHT41采集温湿度

STM32F407-驱动SHT41采集温湿度 SHT41 SHT41通过I2C方式进行驱动 从机地址: 0x44 获取数据方式 1)先发送I2C写,写入特定指令 2)延时一段时间,等待SHT41处理 3)再进行I2C读,读数据即可 一些…

Ansible(二)

一、Playbook基础 1.1 Playbook定义 Playbook其实是Ansible服务的一个配置文件,Ansible使用Playbook的YAML语言配置编写成操作需求,实现对远端主机或策略部署,实现对远端主机的控制与管理。 1.2 Playbook组成 Tasks:任务&…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt常用控件 | 布局管理器 | 垂直布局Vertical Layout 文章编号&#x…

渗透测试-信息收集

网络安全信息收集是网络安全领域中至关重要的一环,它涉及到对目标系统、网络或应用进行全面而细致的信息搜集和分析。这一过程不仅有助于理解目标网络的结构、配置和潜在的安全风险,还能为后续的渗透测试、风险评估和安全加固提供有力的支持。 在网络安…

安卓开发--新建工程,新建虚拟手机,按键事件响应(含:Android中使用switch-case遇到case R.id.xxx报错)

安卓开发--新建工程,新建虚拟手机,按键事件响应 1.前言2.运行一个工程2.1布局一个Button2.2 button一般点击事件2.2 button属性点击事件2.2 button推荐点击事件(含:Android中使用switch-case遇到case R.id.xxx报错) 本…

MATLAB 多项式

MATLAB 多项式 MATLAB将多项式表示为行向量,其中包含按幂次降序排列的系数。例如,方程P(x) X 4 7 3 - 5 9可以表示为 p [1 7 0 -5 9]; 求值多项式 polyval函数用于求一个特定值的多项式。例如,在 x 4 时,计算我们之前的多项式…

命令重装Linux系统,无需登录控制面板

命令重装Linux系统,无需登录控制面板 部分无法登录控制面板使用这个脚本 自动安装安装脚本 wget https://lyvba.com/auto.sh bash auto.sh -d 12 -v 64 -a -p $passwd \--mirror https://mirrors.ustc.edu.cn/debian/安装命令参考 # 自动安装 Debian 10 buster …

基于YOLOV8复杂场景下船舶目标检测系统

1. 背景 海洋作为地球上70%的表面积,承载着人类生活、经济发展和生态系统的重要功能。船舶作为海洋活动的主要载体之一,在海上运输、资源开发、环境监测等方面发挥着重要作用。复杂海洋环境下的船舶目标检测成为了海事管理、海洋资源开发和环境保护等领…

人工智能轨道交通行业周刊-第79期(2024.4.22-5.12)

本期关键词:无人机巡检、车机联控、减速顶、Agent、GraphRAG、RAGFlow 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界铁路那…

《动手学深度学习》V2(11-18)

文章目录 十一、二 模型选择与过拟合和欠拟合1、模型的选择2、过拟合和欠拟合3、估计模型容量4、线性分类器的VC维5、过拟合欠拟合的代码实现 :fire:①生成数据集②定义评估损失③定义训练函数④三阶多项式函数拟合⑤线性函数拟合(欠拟合)⑤高阶多项式函数拟合(过拟合) 十三、权…

【C语言】精品练习题

目录 题目一: 题目二: 题目三: 题目四: 题目五: 题目六: 题目七: 题目八: 题目九: 题目十: 题目十一: 题目十二: 题目十…

「 网络安全常用术语解读 」漏洞利用预测评分系统EPSS详解

1. 概览 EPSS(Exploit Prediction Scoring System,漏洞利用预测评分系统) 提供了一种全新的高效、数据驱动的漏洞管理功能。EPSS是一项数据驱动的工作,使用来自 CVE 的当前威胁信息和现实世界的漏洞数据。 EPSS 模型产生 0 到 1&…

vue 中的 Vuex

Vuex Vuex是什么? 概念:专门在vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间…

2024最新小红书电商落地实操课,从入门到精通,打造爆款方法(16节课)

你是不是经常在小红书上看到各种各样的推广和引流方法,却感觉实际操作起来很困难? 那么,这门2024最新小红书电商落地实操课就是为你量身定制的!从入门到精通,不仅能让你了解电商平台的基本规则和玩法,还能…

ansible------inventory 主机清单

目录 inventory 中的变量 2)组变量[webservers:vars] #表示为 webservers 组内所有主机定义变量,所有组内成 员都有效 ansible_userrootansible_passwordabc1234 3) [all:vars…

[Java EE] 文件IO(一):文件概念与文件系统操作

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀Java …