链式二叉树

news/2024/4/19 22:27:09/文章来源:https://blog.csdn.net/Djsnxbjans/article/details/128086647

链式二叉树

  • 一,相关函数接口实现
    • 1,前序遍历
    • 2,中序遍历
    • 3,后序遍历
    • 4,节点个数
    • 5,叶子结点个数
    • 6,树的高度
    • 7,第K层结点个数
    • 8,查找值为X的结点
    • 9,通过前序遍历数组构建二叉树
    • 10,销毁二叉树
    • 11,层序遍历
    • 12,判断是否为完全二叉树
  • 二,OJ题实战
    • 1,单值二叉树
    • 2,检查两棵树是否相同
    • 3,另一棵树的子树
    • 4,二叉树的前序遍历
    • 5,二叉树的中序遍历
    • 6,二叉树的后序遍历
    • 7,对称二叉树
    • 8,二叉树的建立及遍历
    • 9,判断是否为平衡二叉树

一,相关函数接口实现

所谓链式二叉树,就是存储方式是链式存储的,所以首先要定义出二叉树结点的结构体:

typedef struct TreeNode
{int val;struct TreeNode* left;struct TreeNode* right;
}TreeNode;

为了方便测试后面的函数,在这里手动创建一个二叉树
在这里插入图片描述

TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));if (!node){perror("malloc fail");exit(-1);}node->val = x;node->left = node->right = NULL;return node;
}
int main()
{TreeNode* n1 = BuyTreeNode(1);TreeNode* n2 = BuyTreeNode(2);TreeNode* n3 = BuyTreeNode(3);TreeNode* n4 = BuyTreeNode(4);TreeNode* n5 = BuyTreeNode(5);TreeNode* n6 = BuyTreeNode(6);n1->left = n2;n1->right = n4;n4->left = n5;n4->right = n6;n2->left = n3;return 0;
}

1,前序遍历

前序遍历就是先遍历的顺序为:根节点-左子树-右子树

void PrevOrder(TreeNode* root)
{if (root == NULL){return;}printf("%d ", root->val);PrevOrder(root->left);PrevOrder(root->right);
}

二叉树这里的相关问题都会大量使用递归,为了更直观的看到是如何递归的可以画一下递归展开图:
在这里插入图片描述

2,中序遍历

中序后序与前序没有什么区别就是先遍历根节点与后遍历根节点的区别

void InOrder(TreeNode* root)
{if (root == NULL){return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}

3,后序遍历

void PostOrder(TreeNode* root)
{if (root == NULL){return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->val);
}

4,节点个数

递归采用的是分治思想,不断地把问题进行细分,直到不可细分为止。
数结点个数可以这样看:
对于根节点来说,树的结点数就是根的左子树的节点数+根的右子树的节点数+1(这个1就是根节点)

int TreeSize(TreeNode* root)
{if (root == NULL){return 0;}return TreeSize(root->left) + TreeSize(root->right) + 1;
}

5,叶子结点个数

叶子结点个数与上面的节点个数有所不同,不能每次都加上根节点的‘1’,而是当某个根节点的左右子树都是空树的时候再返回1。

int TreeLeafSize(TreeNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

递归展开图:
在这里插入图片描述

6,树的高度

树的高度思想与树的节点数思想类似,但是有区别:
是左右子树高度大的那一个+根节点的‘1’

int TreeHeight(TreeNode* root)
{if (root == NULL){return 0;}int leftheight = TreeHeight(root->left);int rightheight = TreeHeight(root->right);return leftheight > rightheight ?  leftheight + 1 : rightheight + 1;
}

7,第K层结点个数

第k层是相对于根节点的,那么就相当于左右子树的k-1层,这样分治下去直到k==1就返回1。

int TreeLevelSize(TreeNode* root,int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return TreeLevelSize(root->left, k - 1) + TreeLevelSize(root->right, k - 1);
}

8,查找值为X的结点

如果根节点的值就为x,那么直接返回。否则就先从左子树找,再找不到就去右子树找,直到找到为止,如果树中没有此结点就返回空。

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

9,通过前序遍历数组构建二叉树

后面的一个OJ题:二叉树的建立及遍历与这个问题相同,放在后面讲解。

10,销毁二叉树

销毁二叉树也是采用递归的形式删除,但要注意的是应该先删除左右子树再删除根节点,因为如果先删除根节点就无法找到左右子树了。

void TreeDestory(TreeNode** root)
{if (*root == NULL){return;}TreeDestory(&((*root)->left));TreeDestory(&((*root)->right));free(*root);*root = NULL;
}

11,层序遍历

剩余的两个问题与前面有所不同,前面的问题都是采用递归的方式解决的,层序遍历和判断是否为完全二叉树都是通过借助队列迭代实现的。
首先将根节点进队列,在根节点出队列的时候把左右子树(当左右子树不是空树时)带入到队列中,依次进行,直到队列为空为止。
在这里插入图片描述

void LevelOrder(TreeNode* root)
{Queue q;QueueInit(&q);if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);printf("%d ", front->val);QueuePop(&q);if (front->left){QueuePush(&q, front->left);}if (front->right){QueuePush(&q, front->right);}}QueueDestroy(&q);
}

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

这个问题最好的解决方法就是利用层序遍历,不过与上面的层序遍历有些区别,就是左右子树为空树的时候也入队列,当出队列的元素是NULL时,若是完全二叉树,则此时队列中的元素都是NULL,反之不是完全二叉树。
在这里插入图片描述

bool TreeComplete(TreeNode* root)
{Queue q;QueueInit(&q);if (root){QueuePush(&q, root);}while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){while (!QueueEmpty(&q)){TreeNode* tmp = QueueFront(&q);QueuePop(&q);if (tmp != NULL){return false;}}}if (front){QueuePush(&q, front->left);QueuePush(&q, front->right);}}QueueDestroy(&q);return true;
}

二,OJ题实战

1,单值二叉树

链接: 单值二叉树
在这里插入图片描述

同样采用分治的思想,先比较根与左右子树是否相等,如果不等直接返回false,如果相等,那么左右子树作为新的根节点进行递归。

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

2,检查两棵树是否相同

链接: 检查两棵树是否相同
在这里插入图片描述

思路:先比较根结点如果相同就分治下去左右子树作为新的根,反之则返回false
但是要注意几点特殊情况:
一个根节点为空另一个不为空则返回false
两个根节点都是空则返回true

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

3,另一棵树的子树

链接: 另一棵树的子树

在这里插入图片描述
上面判断两个树是否相等相当于这个问题的子问题,我们只需要依次遍历根结点,左子树,右子树,看是否与subroot是相同的树,如果是就返回true。
注意:如果左子树与subroot相同就不用看右子树了,直接返回true

bool issametree(struct TreeNode* root1,struct TreeNode* root2)
{if(root1==NULL&&root2==NULL){return true;}if(root1==NULL||root2==NULL){return false;}if(root1->val!=root2->val){return false;}return issametree(root1->left,root2->left)&&issametree(root1->right,root2->right);
}bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){if(root==NULL){return false;}if(issametree(root,subRoot)){return true;}bool ret1=isSubtree(root->left,subRoot);if(ret1)return ret1;bool ret2=isSubtree(root->right,subRoot);if(ret2)return ret2;return false;
}

4,二叉树的前序遍历

链接: 二叉树的前序遍历

在这里插入图片描述
OJ题中的前序遍历,是要把遍历的结果放到数组中返回,但是要在传参数的时候要注意,控制数组下标的变量传参时要传指针,否则会有麻烦哦。

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

下面来画一下传参时不传指针造成的后果:
在这里插入图片描述
i是记录数组下标的,应该往数组中放一个元素就改变,而向上图中,将3放到数组中后,返回到上一层栈帧此时的i的值仍为2,所以将4放到数组中的时候会把3覆盖掉。
为了防止这样的错误,我们得采用传i的地址,就不会存在上图中的问题。

5,二叉树的中序遍历

链接: 二叉树的中序遍历

中序后序与前序遍历大同小异

 void InOrder(struct TreeNode* root,int* ret,int* i)
{if(root==NULL){return ;}InOrder(root->left,ret,i);ret[(*i)++]=root->val;InOrder(root->right,ret,i);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize){if(!root){*returnSize=0;return NULL;}int* ret=(int*)malloc(sizeof(int)*100);int i=0;InOrder(root,ret,&i);*returnSize=i;return ret;
}

6,二叉树的后序遍历

链接: 二叉树的后序遍历

 void PostOrder(struct TreeNode* root,int* ret,int* i)
{if(root==NULL){return ;}PostOrder(root->left,ret,i);PostOrder(root->right,ret,i);ret[(*i)++]=root->val;
}int* postorderTraversal(struct TreeNode* root, int* returnSize){if(!root){*returnSize=0;return NULL;}int* ret=(int*)malloc(sizeof(int)*100);int i=0;PostOrder(root,ret,&i);*returnSize=i;return ret;
}

7,对称二叉树

链接: 对称二叉树

在这里插入图片描述
此题与判断两棵树是否相同,非常类似,只需稍加修改即可。
判断两个数是否相同,先判断根结点,再判断root1的左子树与root2的左子树,而对称二叉树只需对比root1的左子树与root2的右子树,这样交叉对比就可以了。

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

8,二叉树的建立及遍历

链接: 二叉树的建立及遍历

在这里插入图片描述
根据给定的输入字符串,我们先创建根结点,再创建左右子树,如果字符是‘#’就返回NULL。
注意:传数组下标i的时候,也要传地址,与上面讲过的问题一样。

#include <stdio.h>
#include<stdlib.h>struct TreeNode
{char val;struct TreeNode* left;struct TreeNode* right;
};
struct TreeNode* TreeCreate(char* str,int* pi)
{if(str[*pi]=='\0'){return NULL;}if(str[*pi]=='#'){(*pi)++;return NULL;}struct TreeNode* root=(struct TreeNode*)malloc(sizeof(struct TreeNode));root->val=str[(*pi)++];root->left=TreeCreate(str,pi);root->right=TreeCreate(str,pi);return root;
}
void InOrder(struct TreeNode* root)
{if(root==NULL){return;}InOrder(root->left);printf("%c ",root->val);InOrder(root->right);
}
int main() {char str[100];scanf("%s",str);int pi=0;struct TreeNode* ret=TreeCreate(str,&pi);InOrder(ret);return 0;
}

9,判断是否为平衡二叉树

链接: 判断是否为平衡二叉树

在这里插入图片描述

这个问题实质就是求二叉树高度函数的复用,每次都判断一下左右子树的高度差,如果大于1就返回false。

int TreeHeight(struct TreeNode* root)
{if(root==NULL){return 0;}int HL=TreeHeight(root->left);int HR=TreeHeight(root->right);return HL>HR ? HL+1:HR+1;
}
bool isBalanced(struct TreeNode* root){if(root==NULL){return true;}int HL=TreeHeight(root->left);int HR=TreeHeight(root->right);if(abs(HL-HR)>1){return false;}return isBalanced(root->left)&&isBalanced(root->right);
}

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

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

相关文章

关于虚拟机中IPI中断的思考

前言 感谢intel的vt-x技术&#xff0c;让虚拟机大部分指令可以直接运行在CPU中&#xff0c;只有少部分敏感指令需要有VMM来模拟执行。其中&#xff0c;每个CPU的LAPIC接收到的中断是虚拟化的开销一个大头。 LAPIC接收到的中断分为外部中断&#xff0c;内部中断&#xff0c;IP…

【SQL Server + MySQL三】数据库设计【ER模型+UML模型+范式】 + 数据库安全性

极其感动&#xff01;&#xff01;&#xff01;当时学数据库的时候&#xff0c;没白学&#xff01;&#xff01; 时隔很长时间回去看数据库的笔记都能看懂&#xff0c;每次都靠这份笔记巩固真的是语雀分享要花钱&#xff0c;要不一定把笔记给贴出来(;༎ຶД༎ຶ) &#xff0c;除…

第2-4-8章 规则引擎Drools实战(1)-个人所得税计算器

文章目录9. Drools实战9.1 个人所得税计算器9.1.1 名词解释9.1.2 计算规则9.1.2.1 新税制主要有哪些变化&#xff1f;9.1.2.2 资较高人员本次个税较少&#xff0c;可能到年底扣税增加&#xff1f;9.1.2.3 关于年度汇算清缴9.1.2.4 个人所得税预扣率表&#xff08;居民个人工资、…

LeetCode - 76 最小覆盖子串

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回…

iClient for Leaflet设置地图掩膜

作者&#xff1a;lly 文章目录背景一、实现思路二、步骤代码三、完整代码背景 最近很多小伙伴需要只展示地图的某个行政区域&#xff0c;由于地图存在多个图层&#xff0c;所以图层过滤的方式并不能很好的适用&#xff0c;这个时候&#xff0c;我们可以考虑给地图覆盖一层掩膜…

界面控件DevExpress WPF的主题设计器,可轻松完成应用主题研发

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 DevExpress WPF的The…

双十二薅羊毛!这几款数码好物不可错过

双十二即将开始&#xff0c;在这段时间里有的人已经将自己心仪的塞满了整个购物车了吧&#xff0c;而有的人还没想好到底要入手什么&#xff0c;如果你也是还在纠结的话&#xff0c;不知道该买什么又或是想知道哪些产品更适合你入手&#xff0c;不妨来看看小编今天为你带来的这…

MySQL第一弹

目录 一、数据库的基本概念 1、数据 (Data) 2、表 3、数据库 4、数据库管理系统(DBMS) 5、数据库系统 6、DBMS的工作模式如下 二、数据库的发展史 1.第一代数据库&#xff08;淘汰&#xff09; 2.第二代数据库&#xff08;现在用的基本上都是二代&#xff09; 3.第…

亲戚小孩月薪17k,而我只有4k+,好慌......

我们总是在悲观与乐观中反复折磨自己&#xff0c;感觉自己一事无成。总是眼高手低&#xff0c;总以为大运会砸到自己&#xff0c;遇到挫折就会感到很沮丧。 大学四年没考到英语六级证书&#xff0c;小学教资考了两次。现在想要考研&#xff0c;但总是觉得来不及&#xff0c;或…

磁盘划分和磁盘格式化

文章目录列出装置的 UUID 等参数parted 列出磁盘的分区表类型与分区信息磁盘分区&#xff1a;gdisk、fdisk用 gdisk 新增分区槽用 gdisk 删除一个分区槽磁盘格式化&#xff08;建立文件系统&#xff09;XFS 文件系统 mkfs.xfsXFS 文件系统 for RAID 效能优化&#xff08;Option…

java中csv导出-追加-列转行

1、问题描述 业务数据量比较大&#xff0c;业务上查询条件写入数据库&#xff0c;java定时去读&#xff0c;然后导出csv&#xff0c;供用户下载&#xff0c;因为有模板要求&#xff0c;前一部分是统计信息&#xff0c;后一部分是明细信息&#xff1b;首先csv中写入统计信息&am…

IDEA的日常快捷键大全

更多内容在&#xff1a;https://javaxiaobear.gitee.io/ ​​​​​​第1组&#xff1a;通用型 说明 快捷键 复制代码-copy ctrl c 粘贴-paste ctrl v 剪切-cut ctrl x 撤销-undo ctrl z 反撤销-redo ctrl shift z 保存-save all ctrl s 全选-select all …

Python连接Clickhouse遇坑篇,耗时一天成功连接!

首先&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;不要看网上那些乱七八糟的使用clickhouse-driver连接了&#xff0c;真tm难用&#xff0c;端口能搞死你那种&#xff0c;超级烦&#xff01; 推荐直接看官方…

数商云SRM系统招标流程分享,助力建筑材料企业降低采购成本,提高采购效率

近年来&#xff0c;随着主管部门对房地产市场的监管非常严格&#xff0c;房地产业的发展已进入瓶颈期&#xff0c;这对与房地产业密切相关的建材行业产生了很大的影响。同时&#xff0c;我国城市化进入成熟期&#xff0c;行业规模发展动力减弱&#xff0c;建材行业增长压力明显…

Kotlin高仿微信-第8篇-单聊

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

VauditDemo靶场代码审计

靶场搭建 将下载好的VAuditDemo_Debug目录复制到phpstudy的www目录下&#xff0c;然后将其文件名字修改成VAuditDemo&#xff0c;当然你也可以修改成其他的 运行phpstudy并且访问install目录下的install.php&#xff0c;这里我访问的是http://127.0.0.1/VAuditDemo/install/in…

竞赛——【蓝桥杯】2022年12月第十四届蓝桥杯模拟赛第二期C/C++

1、最小的2022 问题描述 请找到一个大于 2022 的最小数&#xff0c;这个数转换成二进制之后&#xff0c;最低的 6 个二进制为全为 0 。 请将这个数的十进制形式作为答案提交。 答案提交 这是一道结果填空的题&#xff0c;你只需要算出结果后提交即可。本题的结果为一个整数…

Java学习之继承练习题

目录 第一题 代码 输出流程分析 运行结果 考察知识点 第二题 代码 流程分析 运行结果 第三题 题目要求 我的代码 代码改进 第一题 代码 package com.hspedu.extends_.exercise;public class ExtendsExercise01 {public static void main(String[] args) {B b new …

Sentinel-2(哨兵2数据介绍)

哥白尼 Sentinel-2&#xff08;哨兵 2&#xff09;计划是一个由两颗相同的 Sentinel-2 极轨卫星组成的星座&#xff0c;两颗卫星相位差 180&#xff0c;运行在平均高度 786 km 的太阳同步轨道上。每颗卫星在其轨道上的位置由双频全球导航卫星系统&#xff08;GNSS&#xff09;接…

ggrcs 包2.4绘制RCS(限制立方样条图)实际操作演示(1)

ggrcs 包2.4版本已经发布一段时间了&#xff0c;大概几个月了吧&#xff0c;收到不少好评&#xff0c; 没听说太大的问题&#xff0c;最主要的问题有两个&#xff1a; 1.是说变量不是数字变量。 2.是说数据超过10万&#xff0c;无法处理 第一个问题非常好处理&#xff0c;这…