二叉树——链式结构的实现

首先是分为三个文件进行实现:tree.h、tree.c、test.c

  • tree.h

用链表来表示⼀棵⼆叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩⼦和右孩⼦所在的链结点的存储地址。

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历 
void PostOrder(BTNode* root);// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root);// ⼆叉树叶⼦结点个数
int BinaryTreeLeafSize(BTNode* root);// ⼆叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);//⼆叉树的深度/⾼度
int BinaryTreeDepth(BTNode* root);// ⼆叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);// ⼆叉树销毁
void BinaryTreeDestory(BTNode** root);//层序遍历
void LevelOrder(BTNode* root);//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root);
  • tree.c

前序遍历

访问顺序为:根结点、左子树、右子树
思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 若不为空则打印根结点
  3. 递归根结点的左孩子结点
  4. 递归根结点的右孩子结点
#include"tree.h"void PreOrder(BTNode* root)
{if (root == NULL){return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}

在这里插入图片描述

中序遍历

访问顺序为:左子树、根结点、右子树

思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 若不为空则递归根结点的左孩子结点
  3. 打印根结点
  4. 递归根结点的右孩子结点
void InOrder(BTNode* root)
{if (root == NULL){return;}InOrder(root->left);printf("%d ",root->data);InOrder(root->right);
}

后序遍历

访问顺序为:左子树、右子树、根结点

思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 若不为空则递归根结点的左孩子结点
  3. 递归根结点的右孩子结点
  4. 打印根结点
void PostOrder(BTNode* root)
{if (root == NULL){return;}PostOrder(root->left);PostOrder(root->right);printf("%d ",root->data);
}

⼆叉树结点个数

思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 若不为空,则返回1+递归根结点的左子树+递归根结点的右子树
int BinaryTreeSize(BTNode* root)
{if (root == NULL){return 0;}return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

⼆叉树叶子结点个数

思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 若该结点的左右孩子都为空,则该结点为叶子结点
  3. 返回递归左子树+递归右子树
int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL){return;}if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

⼆叉树第k层结点个数

思路:

  1. 若根结点为空,则表示该树为空,直接返回0
  2. 当k为1时,则表示该结点为第k层,返回1
  3. 递归左子树,并将k-1
  4. 递归右子树,将k-1
  5. 将两个数相加
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

⼆叉树的深度/高度

思路:

  1. 若根结点为空,则表示该树为空,直接返回0
  2. 递归左右子树,计算深度
  3. 比较左右子树的深度大小,将大的深度+1(根结点)
int BinaryTreeDepth(BTNode* root)
{if (root == NULL){return 0;}int leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}

⼆叉树查找值为x的结点

思路:

  1. 若根结点为空,则表示该树为空,直接返回NULL
  2. 若根结点的值与待查找值相同,则返回根结点
  3. 不相同则递归根结点的左子树,观察是否相同
  4. 递归根结点的右子树,观察是否相同
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}BTNode* leftfind=BinaryTreeFind(root->left, x);if (leftfind)return leftfind;BTNode* rightfind = BinaryTreeFind(root->right, x);if (rightfind)return rightfind;return NULL;
}

⼆叉树销毁

思路:

  1. 若根结点为空,则表示该树为空,直接返回
  2. 递归销毁根结点的左子树
  3. 递归销毁根结点的右子树
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}

层序遍历

思路:

  1. 需要借助队列来实现,因此第一步引用队列的操作
  2. 初始化队列,并将根结点插入队列
  3. 将根结点出队,并将根结点的左右子树入队,接着循环,直到队列为空
  4. 销毁队列
#include"queue.h"
void LevelOrder(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q,root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);printf("%d ", front->data);QueuePop(&q);if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}QueueDestroy(&q);
}

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

思路:

  1. 也需要引入队列
  2. 初始化队列,并将根结点插入队列
  3. 将队列队头出队,当队头为空时退出循环,否则将队头的左右孩子入队
  4. 当队头为空时,判断队列是否为空,为空则说明是完全二叉树,否则,不为完全二叉树
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q,root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, root->left);QueuePush(&q,root->right);}while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}
  • test.c

手动创建一棵树:
在这里插入图片描述

#include"tree.h"BTNode* buyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}void Test()
{BTNode* node1 = buyNode(1);BTNode* node2 = buyNode(2);BTNode* node3 = buyNode(3);BTNode* node4 = buyNode(4);node1->left = node2;node1->right = node3;node2->left = node4;PreOrder(node1);printf("\n");InOrder(node1);printf("\n");PostOrder(node1);printf("\n");int size=BinaryTreeSize(node1);printf("size : %d\n", size);size=BinaryTreeSize(node1);printf("size : %d\n", size);int leafsize = BinaryTreeLeafSize(node1);printf("leafsize : %d\n", leafsize);int k = 3;int levelsize=BinaryTreeLevelKSize(node1, k);printf("levelsize : %d\n", levelsize);int high = BinaryTreeDepth(node1);printf("high : %d\n", high);printf("%d\n", BinaryTreeFind(node1,4)->data);LevelOrder(node1);printf("\n");printf("%s\n", BinaryTreeComplete == false ? "不是完全二叉树" : "是完全二叉树");BinaryTreeDestory(&node1);
}int main()
{Test();return 0;
}

请添加图片描述

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

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

相关文章

一键解析:由于找不到xinput1_3.dll,无法继续执行代码的问题,有效修复xinput1_3.dll文件

xinput1_3.dll是一个重要的动态链接库文件&#xff0c;它是DirectX软件包的一部分&#xff0c;主要负责处理游戏和多媒体应用程序中的输入功能。当用户尝试启动某些游戏或应用程序时&#xff0c;可能会遇到一个错误提示&#xff0c;指出“由于找不到xinput1_3.dll&#xff0c;无…

TypeScript 的主要特点和重要作用

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

《昇思25天学习打卡营第三十三天|7月26号》

昇思25天学习打卡营 在昇思25天学习打卡营的第33天7月26号&#xff0c;我深入学习了Python编程。通过课程的系统学习和实践编程项目&#xff0c;我逐渐掌握了Python语言的基本语法和核心概念。 特别是在函数定义和数据结构的应用上&#xff0c;我学习到了一些新的东西。以为平…

苹果手机怎么录屏?一键操作,轻松掌握录屏技巧

最近新换了一台苹果手机&#xff0c;但苹果手机和安卓手机有挺多不相同的地方&#xff0c;就比如苹果手机怎么录屏我一直都没找到&#xff0c;有没有经常使用苹果手机的朋友可以帮帮我&#xff1f;先谢谢大家啦&#xff01;” 苹果手机作为全球领先的智能手机品牌&#xff0c;…

layui 乱入前端

功能包含 本实例代码为部分傻瓜框架&#xff0c;插入引用layui。因为样式必须保证跟系统一致&#xff0c;所以大部分功能都是自定义的。代码仅供需要用layui框架&#xff0c;但原项目又不是layui搭建的提供解题思路。代码较为通用 自定义分页功能自定义筛选列功能行内编辑下拉、…

面试经典算法150题系列-数组/字符串操作之多数元素

序言&#xff1a;今天是第五题啦&#xff0c;前面四题的解法还清楚吗&#xff1f;可以到面试算法题系列150题专栏 进行复习呀。 温故而知新&#xff0c;可以为师矣&#xff01;加油&#xff0c;未来的技术大牛们。 多数元素 给定一个大小为 n 的数组 nums &#xff0c;返回其…

“华数杯”全国大学生数学建模竞赛含金量如何?

“华数杯”全国大学生数学建模竞赛是由华中师范大学主办的一项全国性的大学生数学建模竞赛。该竞赛旨在提高大学生的数学建模能力和实践能力,增强大学生的创新意识和团队协作精神。 搜集一些评价,有人说该竞赛的含金量较高,但是也有一些人认为其认可度不高,报名费用较贵。…

javascript 构造函数

1.定义一个构造函数 命名是大驼峰 不需要显式得返回 this对象 构造函数已返回 2.使用这个构造函数构建对象

锅总浅析链路追踪技术

链路追踪是什么&#xff1f;常用的链路追踪工具有哪些&#xff1f;它们的异同、架构、工作流程及关键指标有哪些&#xff1f;希望读完本文能帮您解答这些疑惑&#xff01; 一、链路追踪简介 链路追踪技术&#xff08;Distributed Tracing&#xff09;是一种用于监控和分析分布…

代码随想录算法训练营day29 | 134. 加油站 、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列

碎碎念&#xff1a;加油 参考&#xff1a;代码随想录 134. 加油站 题目链接 134. 加油站 思想 局部最优&#xff1a; 一旦currentSum为负数&#xff0c;起始位置至少要是i1。 全局最优&#xff1a; 最后可以跑完一圈。 局部最优可以推出全局最优且找不到反例&#xff0c;所…

CST软件进行时域自适应网格设置步骤

这一期&#xff0c;我们回答一个大家非常关注的网格的问题。仿真软件的网格质量直接决定仿真的精度和效率&#xff0c;设置合理的网格才能将仿真做的又快有准。CST的微波工作室有多种求解器&#xff0c;如果用频域求解器&#xff08;F&#xff09;来仿真&#xff0c;有限元算法…

TCP的可靠机制

TCP的可靠机制 前言 要了解TCP的可靠机制&#xff0c;我们必须要先熟悉TCP的报文&#xff0c;在这篇文章中有详细介绍TCP的报文 &#xff1a; 并且确认应答机制也在该文章中提到&#xff0c;所以这篇文章就不会再介绍确认应答了。 超时重传 我们都知道&#xff0c;报文在网…

详解Qt 之QMdiArea 和 QMdiSubWindow

文章目录 前言QMdiArea概念作用为什么需要 QMdiAreaQMdiArea 的主要函数和成员函数列表 QMdiSubWindow概念作用为什么需要 QMdiSubWindowQMdiSubWindow 的主要函数和成员函数列表 示例代码 更多用法... 总结 前言 在复杂的应用程序中&#xff0c;尤其是那些需要同时管理多个子…

RabbitMQ快速入门(MQ的概念、安装RabbitMQ、在 SpringBoot 项目中集成 RabbitMQ )

文章目录 1. 补充知识&#xff1a;同步通讯和异步通讯1.1 同步通讯1.2 异步通讯 2. 同步调用的缺点2.1 业务耦合2.2 性能较差2.3 级联失败 3. 什么情况下使用同步调用4. 异步调用5. 异步调用的优点和缺点5.1 异步调用的优点5.1.1 解除耦合&#xff0c;拓展性强5.1.2 无需等待&a…

SQL必知必会

SQL必知必会 一些SQL知识&#xff0c;出自极客时间陈旸老师《SQL必知必会》 https://time.geekbang.org/column/intro/100029501 基础 视图 视图作为一张虚拟表&#xff0c;帮我们封装了底层与数据表的接口。它相当于是一张表或多张表的数据结果集。视图的这一特点&#x…

DMB,DSB,ISB三个指令区别

此部分说明三个指令的具体区别&#xff08;在指令流水线上说明&#xff09;&#xff0c;这三个指令主要目的在于确保程序在多处理器环境下的稳定性和一致性&#xff0c;避免由于指令乱序和内存操作重排引起的不可预测行为 一个简化的流水线&#xff0c;包含以下阶段&#xff1…

【git】git常用命令提交规范

Git 是程序员工作中不可或缺的版本控制工具&#xff0c;以下是一些优化后的常用 Git 命令列表&#xff0c;旨在帮助你更高效地使用 Git 进行版本控制。 基础操作 拉取代码 git clone xxx.git创建分支 git branch dev切换分支 git checkout dev # 或者 git switch dev创建并切换…

Mirror学习笔记(一) 简介

文章目录 一、常规学习&#xff1a;Mirror核心功能有服务器和主机 二、时间戳批处理时间戳 三、TCP和UDP四、CCU(同时在线人数)五、SyncDirection(同步方向)六、RTT&#xff08;往返时间&#xff09;七、Connection Quality&#xff08;连接质量&#xff09;八、Lag Compensati…

Android mLruProcesses的分布结构

AMS中的进程管理 final ArrayList<ProcessRecord> mLruProcesses new ArrayList<ProcessRecord>(); 在AMS的内部属性中使用mLruProcesses集合保存所有的进程信息&#xff0c;AMS将所有进程按照优先级从低到高的顺序保存着对应的ProcessRecord信息&#xff0c;即排…

25、Python之面向对象:私有属性是掩耳盗铃还是恰到好处

引言 声明&#xff0c;今天的文章中没有一行Python代码&#xff0c;更多的是对编程语言设计理念的思考。 上一篇文章中介绍了关于Python面向对象封装特性的私有属性的相关内容&#xff0c;提到了Python中关于私有属性的实现是通过“名称混淆”的方式来实现的&#xff0c;我们…