当前位置: 首页 > news >正文

二叉树(三)

一、二叉树的遍历

二叉树遍历是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。

1.前序遍历(先根遍历)

前序遍历(Preorder Traversal也叫先序遍历)——根、左子树、右子树。属于DFS(深度优先遍历)。空用N表示。

// 前序遍历空用N表示
void PrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->_data);PrevOrder(root->_left);PrevOrder(root->_right);
}// 前序遍历不打印空
void PrevOrder(BTNode* root)
{if (root){printf("%d ", root->_data);PrevOrder(root->_left);PrevOrder(root->_right);}
}

2.中序遍历(中根遍历)

中序遍历(Inorder Traversal)——左子树、根、右子树。空用N表示。

// 中序遍历空用N表示
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->_left);printf("%d ", root->_data);InOrder(root->_right);
}

3.后序遍历(后根遍历)

后序遍历(Postorder Traversal)——左子树、右子树、根。空用N表示。

// 后序遍历空用N表示
void PostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->_left);PostOrder(root->_right); printf("%d ", root->_data);
}

4.层序遍历

设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。层序遍历是非递归遍历。属于BFS(广度优先遍历)。

需要用到队列的代码,可以将之前写的代码拷贝过来(源代码->添加->现有项)。

// 层序遍历
#include"Queue.h"
void TreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)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);}QueueDestroy(&q);
}

其中Queue.h文件中要修改:

typedef struct BinaryTreeNode* QDataType;//要使用原生类型

二、二叉树结点个数

// 二叉树结点个数(错误示范)
int TreeSize(BTNode* root)
{static int size = 0;//静态if (root == NULL)return 0;else++size;TreeSize(root->_left);TreeSize(root->_right);return size;//打印结果会累加
}

正确写法:递归遍历思路

// 二叉树结点个数,方法一
int size = 0;
int TreeSize(BTNode* root)
{if (root == NULL)return 0;else++size;TreeSize(root->_left);TreeSize(root->_right);return size;
}
int main()
{BTNode* root = CreatBinaryTree();size = 0;printf("二叉树结点个数:%d\n", TreeSize(root));size = 0;printf("二叉树结点个数:%d\n", TreeSize(root));return 0;
}// 二叉树结点个数,方法二
int TreeSize(BTNode* root, int* psize)
{if (root == NULL)return 0;else++(*psize);TreeSize(root->_left, psize);TreeSize(root->_right, psize);return *psize;//可以不要返回值
}
int main()
{BTNode* root = CreatBinaryTree();int size = 0;printf("二叉树结点个数:%d\n", TreeSize(root, &size));size = 0;printf("二叉树结点个数:%d\n", TreeSize(root, &size));return 0;
}

分治(分而治之)递归思路:

// 二叉树结点个数,方法三
int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
int main()
{BTNode* root = CreatBinaryTree();printf("TreeSize:%d\n", TreeSize(root));return 0;
}

三、二叉树叶子结点个数

int TreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->_left == NULL && root->_right == NULL)//只有一个叶子return 1;return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}

四、二叉树高度

为空是0,不为空就是左子树高度和右子树高度中大的加1。

//方法一:
int fmax(int x, int y)
{return x > y ? x : y;
}
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}
//方法二:
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->_left);int rightHeight = TreeHeight(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

 LCR 175. 计算二叉树的深度 - 力扣(LeetCode)下面代码OJ过不了,效率问题

//OJ不能通过
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

五、二叉树第k层节点个数

int TreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;// 子问题return TreeLevelKSize(root->_left, k - 1) + TreeLevelKSize(root->_right, k - 1);
}

六、二叉树查找值为x的节点

若有多个值为x的节点,返回第一次找到的节点,因为找到值为x的节点就不会再往下找了(若左子树找到值为x的节点,就不会再找右子树的节点)。

BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* ret1 = TreeFind(root->_left, x);if (ret1)return ret1;BTNode* ret2 = TreeFind(root->_right, x);if (ret2)return ret2;return NULL;
}

七、二叉树的销毁

如果是空树,不需要销毁。

使用后序遍历,先销毁左子树,在销毁右子树,最后释放根结点。

void TreeDestory(BTNode* root)
{if (root == NULL)return;TreeDestory(root->_left);TreeDestory(root->_right);free(root);
}

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

①层序遍历走,空也进队列;

②遇到第一个空节点时,开始判断,后面全空就是完全二叉树,后面有非空就不是完全二叉树。

bool TreeComplete(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){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

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

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;
BTNode* BuyNode(int x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->_data = x;node->_left = NULL;node->_right = NULL;return node;
}
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;
}
// 前序遍历空用N表示
void PrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->_data);PrevOrder(root->_left);PrevOrder(root->_right);
}
// 中序遍历空用N表示
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->_left);printf("%d ", root->_data);InOrder(root->_right);
}
// 后序遍历空用N表示
void PostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->_left);PostOrder(root->_right); printf("%d ", root->_data);
}
// 二叉树结点个数
int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
// 二叉树叶子结点个数
int TreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->_left == NULL && root->_right == NULL)//只有一个叶子return 1;return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}
// 二叉树的高度:为空是0,不为空就是左子树高度和右子树高度大的加1
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->_left);int rightHeight = TreeHeight(root->_right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{if (root == NULL)return 0;if (k == 1)return 1;return TreeLevelKSize(root->_left, k - 1) + TreeLevelKSize(root->_right, k - 1);
}
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == x)return root;BTNode* ret1 = TreeFind(root->_left, x);if (ret1)return ret1;//return TreeFind(root->_right, x);BTNode* ret2 = TreeFind(root->_right, x);if (ret2)return ret2;return NULL;
}
// 二叉树销毁
void TreeDestory(BTNode* root)
{if (root == NULL)return;TreeDestory(root->_left);TreeDestory(root->_right);free(root);
}
// 层序遍历
#include"Queue.h"
void TreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)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);}QueueDestroy(&q);
}
// 判断二叉树是否是完全二叉树
bool TreeComplete(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){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}
int main()
{BTNode* root = CreatBinaryTree();PrevOrder(root);printf("\n"); InOrder(root);printf("\n");PostOrder(root);printf("\n");printf("TreeSize:%d\n", TreeSize(root));printf("TreeLeafSize:%d\n", TreeLeafSize(root));printf("TreeHeight:%d\n", TreeHeight(root));printf("TreeLevelKSize:%d\n", TreeLevelKSize(root, 3));TreeLevelOrder(root);printf("\n");TreeComplete(root);TreeDestory(root);root = NULL;return 0;
}

相关文章:

二叉树(三)

一、二叉树的遍历 二叉树遍历是按照某种特定的规则&#xff0c;依次对二叉树中的结点进行相应的操作&#xff0c;并且每个结点只操作一次。 1.前序遍历&#xff08;先根遍历&#xff09; 前序遍历&#xff08;Preorder Traversal也叫先序遍历&#xff09;——根、左子树、右…...

05--kubernetes组件与安装

前言&#xff1a;终于写到kubernetes&#xff08;k8s&#xff09;&#xff0c;容器编排工具不止k8s一个&#xff0c;它的优势在于搭建集群&#xff0c;也是传统运维和云计算运维的第一道门槛&#xff0c;这里会列出两种安装方式&#xff0c;详细步骤会在下文列出&#xff0c;文…...

EmguCV学习笔记 VB.Net和C# 下的OpenCv开发 C# 目录

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…...

探索TensorFlow:深度学习的未来

标题&#xff1a;探索TensorFlow&#xff1a;深度学习的未来 在当今快速发展的人工智能领域&#xff0c;TensorFlow无疑是最耀眼的明珠之一。TensorFlow是由Google Brain团队开发的一个开源机器学习框架&#xff0c;它以其强大的灵活性、易用性和高效的性能&#xff0c;迅速成…...

探索地理空间分析的新世界:Geopandas的魔力

文章目录 探索地理空间分析的新世界&#xff1a;Geopandas的魔力背景&#xff1a;为何选择Geopandas&#xff1f;这个库是什么&#xff1f;如何安装这个库&#xff1f;五个简单的库函数使用方法场景应用&#xff1a;Geopandas在实际工作中的应用常见bug及解决方案总结 探索地理…...

如何为网站申请免费SSL证书?

一、准备阶段 确定证书类型&#xff1a; 对于大多数个人博客和小型企业网站&#xff0c;DV&#xff08;域名验证&#xff09;SSL证书已足够使用&#xff0c;因为它仅验证域名所有权&#xff0c;成本较低且验证快速。准备域名&#xff1a; 确保你拥有一个有效的域名&#xff0c…...

Java项目集成RocketMQ

文章目录 1.调整MQ的配置1.进入bin目录2.关闭broker和namesrv3.查看进程确认关闭4.编辑配置文件broker.conf&#xff0c;配置brokerIP15.开放端口109116.重新启动1.进入bin目录2.启动mqnamesrv和mqbroker1.启动 NameServer 并将输出重定向到 mqnamesrv.log2.**启动 Broker 并将…...

如何将 Bamboo agent 能力迁移到极狐GitLab tag 上?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…...

正则表达式入门:Python ‘ re ‘ 模块详解

正则表达式&#xff08;Regular Expression&#xff0c;简称 re&#xff09;是一种强大而灵活的工具&#xff0c;广泛用于字符串匹配、替换和分割等操作&#xff0c;尤其在处理网页爬虫数据时非常有用。Python 提供了 " re " 模块来支持正则表达式的使用&#xff0c;…...

thinkphp8.0+aliapy(支付宝)pc网站支付

环境&#xff1a;宝塔-centOS8.5,php8.3 第一步&#xff1a;安装alipay v3版本的安装依赖包&#xff1b; composer require alipaysdk/openapi:dev第二步&#xff1a;根据官方文档,把支付相关的类引用进来&#xff1b; <?php declare (strict_types 1);namespace app\p…...

高速信号的眼图、加重、均衡

目录 高速信号的眼图、加重、均衡眼图加重均衡线性均衡器CTLE判决反馈均衡器DFE 高速信号的眼图、加重、均衡 眼图 通常用示波器观察接收信号波形的眼图来分析码间串扰和噪声对系统性能的影响&#xff0c;从而估计系统优劣程度&#xff0c;因而眼图分析是高速互连系统信号完整…...

2024年PMP考前冲刺必背的学习笔记,整理好给你!

项目的四大特点:临时性、独特性、变革驱动性和创造商业价值。 项目管理&#xff1a;将知识、技能、工具与技术应用于项目活动&#xff0c;以满足项目的要求 Pestle&#xff1a;P政治&#xff0c;E经济&#xff0c;S社会&#xff0c;T技术&#xff0c;L法律&#xff0c;E环境 …...

增加服务器带宽可以提高资源加载速度吗?

答案是可以的 &#xff0c;增加服务器带宽通常能够提高资源加速速度。带宽是服务器与互联网之间传输数据的速率&#xff0c;它决定了在单位时间内可以传输的数据量。以下是增加带宽如何提高资源加速速度的几个方面&#xff1a; 1.更快的数据传输&#xff1a;带宽增加后&#xf…...

汽车EDI: NAVISTAR EDI对接

Navistar International Corporation 是一家美国商用车辆制造公司&#xff0c;总部位于伊利诺伊州的Lisle。公司以生产中型和重型卡车、公共汽车、柴油发动机和底盘闻名&#xff0c;其产品广泛应用于运输、建筑、和农业等行业。Navistar 的历史可以追溯到1831年&#xff0c;由国…...

【Word多级标题完整设置】设置各级标题样式将多级列表链接到各级标题样式中

Word多级标题完整设置 一、设置各级标题样式主标题样式设置中英文字体、字形以及字号设置段落设置&#xff08;缩进、间距和行距&#xff09; 一级标题样式设置中英文字体、字形以及字号设置段落设置&#xff08;缩进、间距和行距&#xff09; 二级标题样式设置中英文字体、字形…...

不同分辨率下vue页面的高度自适应

1. 使用视口单位 .element { height: 100vh; /* 使得元素高度等于视口高度的100% */ /* 可以减去一部分高度以适应页眉或页脚 */ height: calc(100vh - 100px); } 2. 使用百分比&#xff08;%&#xff09;高度 .parent { height: 100vh; /* 父元素高度等于视口高度 */…...

“野生钢铁侠 “ 稚晖君一连亮出5 款智元人形机器人,地表最强!

打麻将、拆快递、纽扣穿针&#xff0c;还能做 30KG 重物提拉&#xff01; 沉寂一年&#xff0c;稚晖君带着他的二代机器人全家桶重磅回归&#xff0c;秀出的各种新技能令人眼前一亮。 智东西 8 月 18 日报道&#xff0c;今日&#xff0c;" 野生钢铁侠 " 稚晖君一连亮…...

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…...

LeetCode面试题Day12|LC209 长度最小的子数组、LC30 串联所有单词的子串

题目一&#xff1a; 指路&#xff1a; . - 力扣&#xff08;LeetCode&#xff09;209 长度最小的子数组 思路与分析&#xff1a; 滑动窗口&#xff0c;目的在于降低算法的时间复杂度&#xff0c;每次只维护一定长度的数组而非原数组的全部元素。那么既然需要长度&#xff0…...

【开端】JAVA泛型类的使用

一、这是一个类 public class CommonVo<D extends CommonDao> implements Serializable { 我们来探讨一样 CommonVo<D extends CommonDao> 这个尖括号里到底能写啥。 首先这是一个泛型类型D &#xff0c;D类继承了CommonDao&#xff0c;说明尖括号里只要放入一…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...