数据结构11:二叉树的链式结构

文章目录

  • 快速创建链式二叉树
  • 二叉树的遍历
    • 前序、中序、后序
    • 层序
  • 二叉树的基本操作
    • 二叉树的节点个数
    • 二叉树叶节点的个数
    • 二叉树第k层结点个数
    • 二叉树查找值为x的结点
  • 二叉树基础oj练习
    • 单值二叉树
    • 检查两颗树是否相同
    • 对称二叉树
    • 二叉树的前序遍历
    • 另一颗树的子树
  • 二叉树的创建和销毁
    • 二叉树的创建
    • 二叉树的销毁
    • 判断一棵树是否是完全二叉树

在上文中,我们介绍了完全二叉树的顺序存储,本文将介绍非完全二叉树的链式存储。

快速创建链式二叉树

在介绍二叉树的基本操作前,需先要创建一棵二叉树,然后才能了解其相关的基本操作。由于二叉树的创建比较难理解,所以我们先手动创建一个链式二叉树,等到本文后面再介绍链式二叉树的创建方法。
手动创建链式二叉树:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;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;
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式本文后面会介绍

二叉树的遍历

前序、中序、后序

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

在这里插入图片描述

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

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

下面主要分析前序递归遍历,中序与后序图解类似。

前序遍历递归图解
在这里插入图片描述
在这里插入图片描述
前序遍历结果:1 2 3 4 5 6
中序遍历结果:3 2 1 5 4 6
后序遍历结果:3 2 5 6 4 1

层序

层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

在这里插入图片描述
层序遍历的实现要借助队列来实现,首先在队列中插入根节点,然后删除根结点的同时带入根节点的两个子节点,一直循环删除节点的同时带入子节点的操作,直到队列为空。

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{Queue a;QueueInit(&a);QueuePush(&a, root);while (!QueueEmpty(&a)) {BTNode* tmp = QueueFront(&a);if (tmp == NULL){printf("# ");QueuePop(&a);continue;}printf("%c ", tmp->data);QueuePush(&a, tmp->left);QueuePush(&a, tmp->right);QueuePop(&a);}
}

二叉树的基本操作

二叉树的节点个数

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);
}

二叉树叶节点的个数

int BinaryTreeLeafSize(BTNode* root)
{if (root->left == NULL && root->right == NULL)return 1;if (root->left == NULL)return BinaryTreeLeafSize(root->right);if (root->right == NULL)return BinaryTreeLeafSize(root->left);return BinaryTreeLeafSize(root->right) + BinaryTreeLeafSize(root->left);
}

二叉树第k层结点个数

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);
}

二叉树查找值为x的结点

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data == x)return root;BTNode* left = BinaryTreeFind(root->left, x);if (left != NULL)return left;BTNode* right = BinaryTreeFind(root->right, x);if (right != NULL)return right;return NULL;
}

二叉树基础oj练习

单值二叉树

在这里插入图片描述

bool isUnivalTree(struct TreeNode* root) {if(root == NULL)return true;if(root->left == NULL && root->right == NULL)return true;if(root->left != NULL && root->val != root->left->val)return false;if(root->right != NULL && root->val != root->right->val)return false;return isUnivalTree(root->left)&&isUnivalTree(root->right);
}

检查两颗树是否相同

在这里插入图片描述

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {if(p == NULL && q == NULL)return true;if(p == NULL || q == NULL)return false;if(p->val != q->val)return false;return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}

对称二叉树

在这里插入图片描述

bool _isSymmetric(struct TreeNode* left, struct TreeNode* right)
{if(left == NULL && right == NULL)return true;if(left == NULL || right == NULL)return false;if(left->val != right->val)return false;return _isSymmetric(left->left,right->right)&&_isSymmetric(left->right,right->left);
}bool isSymmetric(struct TreeNode* root) {return _isSymmetric(root->left,root->right);
}

二叉树的前序遍历

在这里插入图片描述

 void _preorderTraversal(struct TreeNode* root, int* returnSize,int* a){if (root == NULL)return;a[*returnSize] = root->val;(*returnSize)++;_preorderTraversal(root->left,returnSize, a);_preorderTraversal(root->right,returnSize, a);}int* preorderTraversal(struct TreeNode* root, int* returnSize) {if (root == NULL){*returnSize = 0;return NULL;}int* a = (int*)malloc(sizeof(int) * 100);*returnSize = 0;_preorderTraversal(root, returnSize, a);return a;
}

另一颗树的子树

在这里插入图片描述

bool isSameTree(struct TreeNode* p, struct TreeNode* q) {if(p == NULL && q == NULL)return true;if(p == NULL || q == NULL)return false;if(p->val != q->val)return false;return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){if(root == NULL)return false;if(isSameTree(root,subRoot))return true;return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

二叉树的创建和销毁

二叉树的创建

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{if (a[*pi] == '#'){(*pi)++;return NULL;}BTNode* root = (BTNode*)malloc(sizeof(BTNode));root->data = a[*pi];(*pi)++;root->left = BinaryTreeCreate(a, pi);root->right = BinaryTreeCreate(a, pi);return root;
}

二叉树的销毁

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

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

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{Queue a;QueueInit(&a);QueuePush(&a, root);int judge = 0;while (!QueueEmpty(&a)){if (judge == 0){BTNode* tmp = QueueFront(&a);if (tmp == NULL){judge = 1;QueuePop(&a);continue;}QueuePush(&a, tmp->left);QueuePush(&a, tmp->right);QueuePop(&a);}else{BTNode* tmp = QueueFront(&a);if (tmp == NULL){QueuePop(&a);continue;}QueueDestroy(&a);return false;}}QueueDestroy(&a);return true;
}

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

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

相关文章

谷雨时节,雨水渐多湿气旺盛,吃什么养生?听听张婉如医生怎么说

谷雨春光晓,山川黛色青。 叶间鸣戴胜,泽水长浮萍。 4月19日21时59分迎来谷雨,雨生百谷,这是谷雨节气的意思,它是春季的最后一个节气,这个时节早晚温差大,空气湿气重,如何养生呢&am…

java在线问卷调查系统的设计与实现(springboot+mysql源码+文档)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线问卷调查系统。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 基于java的在线问卷调查…

linux内核源码分析--通用函数指针

除了稍早讨论的net_device 结构的列表管理字段外,还有一些字段用于管理一些结构,确保这些结构在不需要时能予以删除。 atomic_t refcnt 引用计数,此计数器变为零之前,设备无法除名,参见第八章。 int watchdog_timeo st…

【QT进阶】Qt http编程之json解析的简单介绍

往期回顾 【QT进阶】Qt http编程之后端API测试工具postman使用介绍-CSDN博客 【QT进阶】Qt http编程之http相关类的简单介绍-CSDN博客 【QT进阶】Qt http编程之用户登录注册功能实现-CSDN博客 【QT进阶】Qt http编程之json解析的简单介绍 一、JSON字符串 1、基本概念 JSON字…

电脑便签怎么固定位置 能固定在桌面的电脑便签

在繁忙的工作中,电脑便签是我离不开的小助手。每当灵感闪现,或是需要记录待办事项时,我总会打开便签,快速地记录下来。它就像我电脑屏幕上的一块“记事板”,随时提醒我未完成的工作和即将到来的任务。 但有一段时间&a…

i管家空间不足提醒怎么关闭

i管家的空间不足提醒是为了提醒用户手机存储空间不足,可能会影响手机的正常运行。目前,这个提醒功能是无法直接关闭的。如果您希望减少这类提醒的出现,可以尝试以下几种方法: 清理手机存储:检查手机中是否有不需要的文…

Unity3D 多人战场Animation优化详解

在Unity3D中,实现多人战场动画优化是一个非常重要的任务。动画在游戏中扮演着非常重要的角色,它能够让游戏更加生动和真实。然而,在多人战场中,同时播放多个角色的动画会给游戏性能带来很大的压力。因此,我们需要采取一…

JavaWeb--JS正则表达式

目录 1. 简介 1.1. 语法 1.1.1. 使用RegExp构造函数创建正则表达式 1.1.2. 使用正则表达式字面量语法创建正则表达式 1.1.3. 正则表达式的应用 2. 修饰符 3. 方括号 4. 元字符 5. 量词 6. RegExp对象方法 7. 支持正则的String的方法 8. 正则表达式体验 8.1. 验证 …

restful请求风格的增删改查-----查询and添加

一、restful风格的介绍 restful也称之为REST ( Representational State Transfer ),可以将它理解为一种软件架构风格或设计风格,而不是一个标准。简单来说,restful风格就是把请求参数变成请求路径的一种风格。例如,传统的URL请求…

rk3568死机调试

结论 有两种死机: 一种是有异常栈,此种情况应该是由于linux的实时补丁导致的,去掉实时补丁后未复现;一种无异常栈,但是打印mmc异常:mmc0: cache flush error -110,此种情况需要加打印继续定位。无异常栈死机 无异常栈死机是由于MMC初始化失败导致,根本原因是系统启动…

iOS原生与H5交互方法

UIWebView Objective-C 调用 JavaScript 在使用UIWebView时,可以使用stringByEvaluatingJavaScriptFromString:方法来执行JavaScript代码。 示例代码: NSString *result [webView stringByEvaluatingJavaScriptFromString:"returnFunction()&q…

Kubesphere使用教程

一、简介 KubeSphere是一个开源的容器平台,它提供了Kubernetes集群的部署、运维和管理能力,并且具有友好的Web UI界面,降低了Kubernetes的使用门槛。本教程将引导你逐步了解KubeSphere的基本使用。 二、环境准备 准备至少三台服务器或虚拟…

Darknet,看过很多篇,这个最清晰了

Darknet深度学习框架:YOLO背后的强大支持 Darknet,一个由Joseph Redmon开发的轻量级神经网络框架,以其在计算机视觉任务,特别是目标检测中的卓越表现而闻名。本文将详细介绍Darknet的基本概念、结构以及它在深度学习领域的应用。…

UE4_动画基础_根运动Root Motion

学习笔记,仅供参考! 在游戏动画中,角色的碰撞胶囊体(或其他形状)通常由控制器驱动通过场景。然后来自该胶囊体的数据用于驱动动画。例如,如果胶囊体在向前移动,系统就会知道在角色上播放一个跑步…

Kivy Pyinstaller Windows 打包

各种报错 ImportErrorWhenRunningHook: Failed to import module __PyInstaller_hooks_0_kivy required by hook for module 三天美好时光啥也没干,就研究这个了。 打包成功,运行应用程序exe闪退的。终于打包成功了。 这所有的原因都是因为我爱你。如果…

请编写一个函数int fun(int*s,int t,int *k),用来求出数组的最大元素在数组中的下标并存放在k所指的存储单元中。

本文收录于专栏:算法之翼 https://blog.csdn.net/weixin_52908342/category_10943144.html 订阅后本专栏全部文章可见。 本文含有题目的题干、解题思路、解题思路、解题代码、代码解析。本文分别包含C语言、C++、Java、Python四种语言的解法和详细的解析。 题干 请编写一个函…

小型架构实验模拟

一 实验需求 二 实验环境 22 机器: 做nginx 反向代理 做静态资源服务器 装 nginx keepalived filebeat 44机器: 做22 机器的备胎 装nginx keepalived 99机器:做mysql的主 装mysqld 装node 装filebeat 77机器:做mysq…

pytorch 今日小知识2——F.avg_pool2d、clamp

今天看到 def gem(self, ipts):return F.avg_pool2d(ipts.clamp(minself.eps).pow(self.p), (1, ipts.size(-1))).pow(1. / self.p) 这个函数中的F.avg_pool2d 不是很理解就查了一下 ipts.clamp(1.0e-6): 这个操作将ipts中的每个元素限制在[1.0e-6, inf)的范围内。也就是说&a…

【Python】——字典

🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL&#xff1a…

【python】一文读懂python函数

【python】一文读懂python函数 文章目录 【python】一文读懂python函数(一)简单入门理解函数(二)函数的基本结构:(三)函数的默认值(四)可变参数(五)基于字典的可变参数(**可变参数)(六)函数中变量的作用域(七)lambda函数(八) 过滤函数filter()在Python中,…