C数据结构:二叉树(下)

C数据结构:二叉树(下)

1.二叉树递归结构遍历
2.例题
3.二叉树的性质

1.二叉树递归结构遍历

我们先创建一个如下图所示的二叉树。
在这里插入图片描述

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;node4->left = node5;node4->right = node6;node2->left = node3;return node1;
}
前序遍历

前序遍历即是按照 根、左子树、右子树 的顺序,通过递归结构来遍历。用N代表空树,根据下图可得到前序遍历的序列:1 2 3 N N N 4 5 N N 6 N N
在这里插入图片描述
前序代码实现:

void PrevOrder(BTNode* root)//前序
{if (root == NULL){printf("N ");return;}elseprintf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}

在这里插入图片描述

中序遍历

中序遍历即是按照 左子树、根、右子树 的顺序遍历。遍历序列:N 3 N 2 N 1 N 5 N 4 N 6 N 。
在这里插入图片描述
中序代码实现:

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

在这里插入图片描述

后序遍历

后序遍历即是按照 左子树、右子树、根 的顺序遍历。遍历序列:N N 3 N 2 N N 5 N N 6 4 1 。
在这里插入图片描述
后序代码实现:

void BackOrder(BTNode* root)//后序
{if (root == NULL){printf("N ");return;}else{BackOrder(root->left);BackOrder(root->right);printf("%d ", root->data);}
}

在这里插入图片描述

二叉树的销毁

销毁二叉树应选择后序,若选择前序,销毁根后就找不到左右子树;选择中序,销毁根后就找不到右子树,前序、中序都会导致内存泄漏。所以应先销毁左右子树,再销毁根。

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

2.例题

解决二叉树的相关题目,关键是学会拆分成左右子树递归来解决。

求二叉树节点个数

二叉树的节点是由左子树的节点、右子树的节点和根节点组成,写一个求二叉树节点个数的函数,用这个函数求左右子树的节点个数,再加上根节点,即求得整个二叉树的节点个数。

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);
}
求树的高度

二叉树的高度为最大层数,可以把二叉树拆分成左右子树,再分别求左右子树的高度,比较后得到高度最大的,再加上根节点,就求出了二叉树的高度。

int TreeHeight(BTNode* root)//树的高度
{if (root == NULL)return 0;BTDataType leftHeight = TreeHeight(root->left);BTDataType rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
二叉树第k层的节点个数

例如下图的一颗二叉树,若求第3层的节点数,即k=3,可以发现,对于第一层,k=3;对于第二层,k=2;对于第三层,k=1。所以,同样拆分成左右子树,每次递归时通过k-1调整k,当k=1时就返回1,最后再把左右子树求得的第k层的节点数加起来。
在这里插入图片描述
在这里插入图片描述

int TreeLevelKSize(BTNode* root, int k)//二叉树第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的节点时,就返回该节点。

BTNode* TreeFindX(BTNode* root, BTDataType x)//查找值为为x的节点
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* ret1=TreeFindX(root->left, x);if (ret1)return ret1;BTNode* ret2 = TreeFindX(root->right, x);if (ret2)return ret2;return NULL;
}
前序遍历二叉树并返回数组

前序遍历一颗二叉树,将二叉树的数据放到数组中并返回数组。

返回数组就需要返回指向数组的指针和数组长度,而数组长度就为二叉树的节点个数。

int TreeSize(BTNode* root)//求二叉树节点个数
{return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
void preOrder(BTNode* root,int* a,int* pi)//前序遍历二叉树并把数据放入数组
{if(root==NULL)return;a[(*pi)++]=root->data;preOrder(root->left,a,pi);preOrder(root->right,a,pi);
}
int* preOrderTraversal(BTNode* root,int* returnSize)
{*returnSize=TreeSize(root);//数组长度int* a(int*)malloc((*returnSize)*sizeof(int));//开辟数组int i=0;preOrder(root,a,&i);return a;
}

访问数组需要知道数组长度,C语言不支持函数返回数组,我们期望经过函数处理数组后得到对应的数组长度,所以我们在主函数定义returnSize=0,将returnSize的地址传入函数,因为如果要通过函数改变主函数中变量的值,就要传址调用,这样就得到了数组长度。

根据前序遍历构建二叉树并输出中序遍历

输入前序遍历的字符串,以此建立一个二叉树,再输出中序遍历结果。#表示空树。

这道题的关键是根据前序遍历构建二叉树,所以要前序遍历函数来写创建二叉树的函数。

BTNode* CreateTree(char* str,int* pi)
{if(str[(*pi)]=='#'){(*pi)++;return NULL;}BTNode* root=(BTNode*)malloc(sizeof(BTNode));root->data=str[(*pi)++];root->left=CreateTree(str,pi);root->right=CreateTree(str,pi);return root;
}
void InOrder(BTNode* root)
{if(root==NULL){printf("#");return;}InOrder(root->left);printf("%c",root->data);InOrder(root->right);
}
int main()
{char str[100];scanf("%s",str);printf("\n");int i=0;BTNode* root=CreateTree(str,&i);InOrder(root);printf("\n");return 0;
}

例如,输入前序序列abc##de#g##f###
在这里插入图片描述
在这里插入图片描述

3.二叉树的性质

  • 非空二叉树的第 i 层最多有2^(i-1)个节点。

  • 高度为h的二叉树的最大节点数为2^(h) - 1。

  • 对任意二叉树,度为0的叶有n0个,度为2的节点有n2个,满足n0 = n2 + 1 。

若一颗完全二叉树有767个节点,则叶的个数是多少?

我们设度为0的节点有N0个,度为1的节点有N1个,度为2的节点有N2个,则N0+N1+N2=767,又在完全二叉树中,度为1的节点数要么为0,要么为1,因为N0 = N2 + 1,所以2N0 + N1 - 1 = 767 ,767为奇数,所以2N0 + N1 - 1也应为奇数,2N0显然为偶数,所以N1应为0,这样等式左边才为奇数,所以最终N0为384,即叶数为384。

拙作一篇,望诸位同道不吝斧正。

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

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

相关文章

Linux系统的网络管理(一)

一、网络参数配置:搭建稳定网络基础网络参数配置是 Linux 网络管理的起点,根据操作方式可分为图形化配置、命令行配置和配置文件配置,不同方式适用于不同场景(临时调试 / 永久生效)。1. 图形化配置:依赖 Ne…

Web程序设计

一、控件基础 文本框、按钮事件的使用 <% Page Language"C#" AutoEventWireup"true" CodeFile"User_Login.aspx.cs" Inherits"User_Login" %><!DOCTYPE html><html xmlns"http://www.w3.org/1999/xhtml"&g…

复合设计模式

复合设计模式复合设计模式是一种结构模式&#xff0c;可让您统一处理单个对象和对象的组合。它允许您构建树状结构&#xff08;例如&#xff0c;文件系统、UI 层次结构、组织结构&#xff09;&#xff0c;客户端可以使用同一界面处理单个元素和元素组。它在以下情况下特别有用&…

使用 Prometheus 监控服务器节点:Node Exporter 详解与配置

前言 在上一篇文章中&#xff0c;我们介绍了如何在 CentOS 上部署 Prometheus 并使用 systemd 进行管理。本文将继续深入&#xff0c;讲解如何使用 Prometheus 监控服务器节点&#xff0c;重点介绍 Node Exporter 的作用、安装和配置方法。 Node Exporter 是 Prometheus 生态…

C# 编写一个XmlToDota的转换工具

以下代码可以将Labelme标注的旋转框Xml格式文件转换为Yolo标注格式的txt文件&#xff0c;以便用Yolo OBB训练自己的数据集&#xff1a;using System; using System.Collections.Generic; using System.IO; using System.Xml; using System.Linq; using System.Globalization;na…

[Android] 人体细胞模拟器1.5

[Android] 人体细胞模拟器1.5 链接&#xff1a;https://pan.xunlei.com/s/VOYVUieTpjNVJq-bMys4EEDGA1?pwdm7m6# 省流:这个软件的开发者有点逆天&#xff0c;一个模拟人体器官的软件&#xff0c;细致到有血液报告&#xff0c;还缝合了生理学和病理学&#xff0c;甚至还能做切…

【Linux基础知识系列】第一百一十篇 - 使用Nmap进行网络安全扫描

在网络安全管理中&#xff0c;了解网络中的设备、开放的端口以及运行的服务是至关重要的。Nmap&#xff08;Network Mapper&#xff09;是一个功能强大的开源工具&#xff0c;用于网络发现和安全审计。它可以扫描网络中的设备&#xff0c;识别开放的端口和运行的服务&#xff0…

【Linux仓库】进程的“夺舍”与“飞升”:exec 驱动的应用现代化部署流水线

&#x1f31f; 各位看官好&#xff0c;我是egoist2023&#xff01; &#x1f30d; Linux Linux is not Unix &#xff01; &#x1f680; 今天来学习exec系列的进程程序替换,从"fork"的"克隆"到"exec"的"重生"。 &#x1f44d; 如果觉…

Reachability Query

题目分析 该代码实现了一个动态集合管理系统&#xff0c;支持三种操作&#xff1a;合并集合、切换元素状态、查询集合中是否- 存在活跃元素。核心数据结构为并查集&#xff0c;结合状态标记数组和计数器。关键数据结构与函数 初始化 fa[N]&#xff1a;并查集父节点数组&#xf…

SSL移动接入方案和移动资源发布

一、SSL VPN概述SSL VPN是一种基于SSL/TLS协议的远程安全接入技术&#xff0c;因其广泛兼容Web浏览器&#xff0c;支持“无客户端”部署&#xff0c;具备易于使用和维护的特点。它通过插件系统支持非Web类TCP/UDP应用&#xff0c;并且支持对用户的访问可以做出限制&#xff0c;…

C++STL---count() 统计容器中特定元素出现次数

在 C 标准库中&#xff0c;count 是一个用于统计容器中特定元素出现次数的函数&#xff0c;定义在 <algorithm> 头文件中。它可以快速计算某个值在容器&#xff08;如数组、vector、list 等&#xff09;中出现的次数&#xff0c;避免手动编写循环计数的麻烦。 一、函数原…

Tesla自动驾驶域控制器(AutoPilot HW)的系统化梳理

目前网络上对Tesla自动驾驶硬件&#xff08;AP1-AP4、HW1.0-HW4.0&#xff09;迭代的相关介绍比较混乱&#xff0c;本文这里进行系统化梳理并澄清&#xff0c;并对一些错误进行更正。1、AutoPilot HW迭代图图1 AutoPilot HWMCU迭代图图2 AutoPilot HW 散热设计迭代图&#xff0…

C 语言:第 20 天笔记:typedef(类型重命名规则、应用场景与实战案例)

C语言&#xff1a;第20天笔记 内容提要 构造类型枚举类型typedef综合案例:斗地主预处理 构造类型&#xff1a;枚举类型 使用建议 如果定义不相干的常量&#xff0c;使用宏定义&#xff08;符号常量&#xff09;&#xff1b;如果需要定义一组相关联的常量&#xff08;如月份011、…

在 vue3 和 vue2 中,v-for 和 v-if 可以一起用吗,区别是什么

在 Vue 2 和 Vue 3 中&#xff0c;v-for 和 v-if 可以一起使用&#xff0c;但两者在处理顺序和推荐用法上存在明显区别&#xff0c;主要体现在优先级和最佳实践上&#xff1a; 1. Vue 2 中的 v-for 与 v-if优先级&#xff1a;v-for 的优先级高于 v-if。 这意味着 Vue 会先循环渲…

Linux-进程相关函数

文章目录Linux-进程相关函数父子进程关系父子进程地址空间getpid函数 获取本进程号getppid函数 获取当前进程的进程的父进程号getpgid函数 获取进程组号示例fork函数 创建进程区分父子进程exit函数 进程退出wait函数 等待子进程退出waitpid函数Linux-进程相关函数 每个进程都由…

数据挖掘 6.1 其他降维方法(不是很重要)

6.1 Other dimensionality reduction methods 6.1 其他降维方法 其他降维方法前言问题答案流形3 降维大纲3.1 线性方法3.2 非线性方法3.2.1 流形学习方法&#xff08;Manifold Learning&#xff09;3.2.2 概率方法&#xff08;Probabilistic Approaches&#xff09;3.2.3 拓扑数…

Unity中的特殊文件夹

一.工程路径获取print(Application.dataPath);只用于游戏开发编辑器模式下&#xff0c;游戏发布后此路径就不存在了二.Resources 资源文件夹//路径获取: //一般不获取 //只能使用Resources相关API进行加载 //如果硬要获取 可以用工程路径拼接print(Application.dataPath "…

Seaborn数据可视化实战:Seaborn高级使用与性能优化教程

Seaborn最佳实践与技巧 学习目标 本课程将深入探讨Seaborn库的高级使用技巧&#xff0c;包括性能优化、常见问题解决方法等&#xff0c;旨在帮助学员掌握如何高效地使用Seaborn进行数据可视化&#xff0c;提升图表的美观度和信息传达效率。 相关知识点 Seaborn最佳实践与技巧 学…

分布式系统与单机系统的优劣势对比

近期有遇到一个本地部署的需求&#xff0c;他们希望用主备方案&#xff0c;这就涉及到了备用系统怎么收费的问题。我们是单机系统&#xff0c;其他友商是分布式系统&#xff0c;那20坐席的手拨需求到底是选单机系统好&#xff0c;还是选分布式系统好呢&#xff1f;了解了两者的…

深度学习:从手写数字识别案例认识pytorch框架

目录 一、PyTorch 核心优势与框架定位 二、实战基础&#xff1a;核心库与数据准备 1. 关键库导入与功能说明 2. MNIST 数据集加载与可视化 &#xff08;1&#xff09;数据集下载与封装 &#xff08;2&#xff09;数据集可视化&#xff08;可选&#xff09; 3. DataLoade…