数据结构【链试结构二叉树】

 


🌟个人主页:落叶

目录

 ​编辑

实现链式结构⼆叉树

前中后序遍历:

遍历规则

代码实现

前序遍历:

中序遍历:

后序遍历:

图解遍历:

函数递归栈帧图:

结点个数以及高度等

【⼆叉树】结点个数

【二叉树】叶子节点个数

【二叉树】第k层节点个数

【二叉树】的深度/⾼度

【二叉树】查找值为x的结点 

【二叉树】销毁

层序遍历

判断是否为完全二叉树


🔥摘要:设⼆叉树的根结点所在层数 为1,层序遍历就是从所在⼆叉树的根结点出发,⾸先访问第⼀层的树根结点,然后从左到右访问第2 层上的结点,接着是第三层的结点,以此类推,⾃上⽽下,⾃左⾄右逐层访问树的结点的过程就是层 序遍历。根结点的左⼦树和右⼦树分别⼜是由⼦树结点、⼦树结点的左⼦树、⼦树结点的右⼦树组成的,因此 ⼆叉树定义是递归式的,后序链式⼆叉树的操作中基本都是按照该概念实现的。回顾⼆叉树的概念,⼆叉树分为空树和⾮空⼆叉树,⾮空⼆叉树由根结点、根结点的左⼦树、根结点 的右⼦树组成的。根结点、左⼦树、右⼦树。

实现链式结构⼆叉树

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

创建二叉树数据:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int data;
typedef struct Tree
{int arr;    //数值struct Tree* zuo;//左孩子struct Tree* you;//右孩子
}BT;

⼆叉树的创建⽅式⽐较复杂,为了更好的步⼊到⼆叉树内容中,我们先⼿动创建⼀棵链式⼆叉树

我们进行连接后就成下面这个二叉树


当然我们也可以这样看

//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;}int main()
{p();return 0;
}

回顾⼆叉树的概念,⼆叉树分为空树和⾮空⼆叉树,⾮空⼆叉树由根结点、根结点的左⼦树、根结点 的右⼦树组成的

根结点的左⼦树和右⼦树分别⼜是由⼦树结点、⼦树结点的左⼦树、⼦树结点的右⼦树组成的,因此 ⼆叉树定义是递归式的,后序链式⼆叉树的操作中基本都是按照该概念实现的。

前中后序遍历:

⼆叉树的操作离不开树的遍历,我们先来看看⼆叉树的遍历有哪些⽅式

遍历规则

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

(1)前序遍历(PreorderTraversal亦称先序遍历):访问根结点的操作发⽣在遍历其左右⼦树之前

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

(2)中序遍历(InorderTraversal):访问根结点的操作发⽣在遍历其左右⼦树之中(间)

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

(3)后序遍历(PostorderTraversal):访问根结点的操作发⽣在遍历其左右⼦树之后

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

代码实现
前序遍历:

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

//前序遍历-(根-左-右)
void qian(BT* root)
{if (root == NULL){return;}printf("%d ", root->arr);//左子树qian(root->zuo);//右子树qian(root->you);
}



结果:

//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;qian(n1);printf("\n");}int main()
{p();return 0;
}

中序遍历:

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

//中序遍历-(左-根-右)
void zho(BT* root)
{if (root == NULL){return;}//左子树zho(root->zuo);printf("%d ", root->arr);//右子树zho(root->you);
}



结果:

//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*/zho(n1);printf("\n");}int main()
{p();return 0;
}

后序遍历:

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

//后序遍历
void ho(BT* root)
{if (root == NULL){return;}//左子树ho(root->zuo);//右子树ho(root->you);printf("%d ", root->arr);
}



结果:

//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*/ho(n1);}int main()
{p();return 0;
}

图解遍历:

以前序遍历为例:


函数递归栈帧图:


前序遍历结果:123456

中序遍历结果:321546

后序遍历结果:315641


结点个数以及高度等
【⼆叉树】结点个数

// ⼆叉树结点个数 
int BinaryTreeSize(BT* root)
{if (root == NULL){return 0;}//                左子树                     右子树return 1+ BinaryTreeSize(root->zuo)+ BinaryTreeSize(root->you);
}



结果:

//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*///ho(n1);// ⼆叉树结点个数 printf("size:%d \n", BinaryTreeSize(n1));}int main()
{p();return 0;
}

【二叉树】叶子节点个数

// ⼆叉树叶⼦结点个数 
int BinaryTreeLeafSize(BT* root)
{if (root == NULL){return 0;}//左子树和右子树都等于空,就是叶子节点if (BinaryTreeLeafSize(root->zuo) == NULL && BinaryTreeLeafSize(root->you) == NULL){return 1;}return BinaryTreeLeafSize(root->zuo) + BinaryTreeLeafSize(root->you);
}



结果:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Tree.h"
//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*///ho(n1);// ⼆叉树结点个数 //printf("size:%d \n", BinaryTreeSize(n1));//叶子节点个数printf("叶子节点:%d\n", BinaryTreeLeafSize(n1));}int main()
{p();return 0;
}

【二叉树】第k层节点个数

// ⼆叉树第k层结点个数 
int BinaryTreeLevelKSize(BT* root, int k)
{if (root == NULL){return 0;}//k等于1了就返回1if (k == 1){return 1;}return BinaryTreeLevelKSize(root->zuo, k - 1) + BinaryTreeLevelKSize(root->you, k - 1);
}



结果:

这里加了2个节点5和6,就和上面那张图一样了。

#define _CRT_SECURE_NO_WARNINGS 1
#include"Tree.h"
//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*///ho(n1);// ⼆叉树结点个数 //printf("size:%d \n", BinaryTreeSize(n1));// 叶子节点个数//printf("叶子节点:%d\n", BinaryTreeLeafSize(n1));//k层节点个数printf("k: %d \n", BinaryTreeLevelKSize(n1, 3));}int main()
{p();return 0;
}

【二叉树】的深度/⾼度

//⼆叉树的深度/⾼度
int BinaryTreeDepth(BT* root)
{if (root == NULL){return 0;}//遍历左子树,把值给zuoint zuo = BinaryTreeDepth(root->zuo);//遍历右子树,把值给youint you = BinaryTreeDepth(root->you);//进行判断return zuo > you ? zuo + 1:you + 1;
}



结果:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Tree.h"
//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*///ho(n1);// ⼆叉树结点个数 //printf("size:%d \n", BinaryTreeSize(n1));// 叶子节点个数//printf("叶子节点:%d\n", BinaryTreeLeafSize(n1));k层节点个数//printf("k: %d \n", BinaryTreeLevelKSize(n1, 3));//⼆叉树的深度/⾼度printf("高度:%d \n", BinaryTreeDepth(n1));}int main()
{p();return 0;
}

【二叉树】查找值为x的结点 

// ⼆叉树查找值为x的结点 
BT* BinaryTreeFind(BT* root, data x)
{if (root == NULL){return NULL;}//等于x,返回当前节点if (root->arr == x){return root;}//zuo接收节点BT* zuo = BinaryTreeFind(root->zuo, x);if (zuo){//返回节点return zuo;}//you接收节点BT* you = BinaryTreeFind(root->you, x);if (you){//返回节点return you;}
}


左子树找不到,就找右子树


结果:

#define _CRT_SECURE_NO_WARNINGS 1
#include"Tree.h"
//申请空间
BT* koj(data x)
{//申请节点BT* tab = (BT*)malloc(sizeof(BT));if (tab == NULL){perror("malloic");exit(1);}tab->arr = x;tab->zuo= tab->you = NULL;return tab;
}
void p()
{//创建节点BT* n1 = koj(1);BT* n2 = koj(2);BT* n3 = koj(3);BT* n4 = koj(4);//BT* n5 = koj(5);//BT* n6 = koj(6);//进行连接n1->zuo = n2;n1->you = n3;n2->zuo = n4;//n2->you = n5;//n3->zuo = n6;/*qian(n1);printf("\n");*//*zho(n1);printf("\n");*///ho(n1);// ⼆叉树结点个数 //printf("size:%d \n", BinaryTreeSize(n1));// 叶子节点个数//printf("叶子节点:%d\n", BinaryTreeLeafSize(n1));k层节点个数//printf("k: %d \n", BinaryTreeLevelKSize(n1, 3));⼆叉树的深度/⾼度//printf("高度:%d \n", BinaryTreeDepth(n1));// ⼆叉树查找值为x的结点 BT* tab = BinaryTreeFind(n1, 4);printf("%s\n", tab == NULL ? "没找到" : "找到了");}int main()
{p();return 0;
}

【二叉树】销毁



// ⼆叉树销毁
void BinaryTreeDestory(BT** root)
{if (*root == NULL){return;}//二级指针,需要传一级指针地址BinaryTreeDestory(&(*root)->zuo);BinaryTreeDestory(&(*root)->you);//释放空间free(*root);*root = NULL;
}

图解析:


结果:

我们可以看到全部销毁了。


层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对⼆叉树进⾏层序遍历。设⼆叉树的根结点所在层数 为1,层序遍历就是从所在⼆叉树的根结点出发,⾸先访问第⼀层的树根结点,然后从左到右访问第2 层上的结点,接着是第三层的结点,以此类推,⾃上⽽下,⾃左⾄右逐层访问树的结点的过程就是层 序遍历

实现层序遍历需要额外借助数据结构:队列


创建队列,初始化,把根节点入队列

循环队列不为空,取队头打印,出队头。

然后判断左子树和右子树,是不是空,不是空就入队列。

销毁队列。

//层序遍历
//借助数据结构--队列
void LevelOrder(BT* root)
{Queue add;//初始化Queuecsh(&add);//入数据Queue_ruwei(&add, root);while (!buer(&add)){//取队头-打印BT* tab = qto(&add);printf("%d ", tab->arr);//出队Queue_chu(&add);//判断是不是空, 队头节点的左右孩子入,队列if (tab->zuo){Queue_ruwei(&add, tab->zuo);}if (tab->you){Queue_ruwei(&add, tab->you);}}//队列销毁Queuexiaoh(&add);
}

结果:


判断是否为完全二叉树


注意:

如果是完全二叉树,跳出循环之后队列里都是NULL。

如果不是完全二叉树,跳出循环之后队列里,还有非空节点。

思路:

创建一个队列,把根节点入队列,循环队列里不为空。

取队头节点,然后出队,判断这个节点是不是空,是空跳出循环。

不是空,左子树和右子树入队列。

是完全二叉树的话剩下的都是空,

循环取出队头数据,出队,进行判断,不等于空的话还有非空节点,那就是不完全二叉树了,返回false。

最后循环都为空,是完全二叉树,返回true。


bool pdercs(BT* root)
{Queue add;//队列初始化Queuecsh(&add);//入队列Queue_ruwei(&add, root);while (!buer(&add)){//取队头数据BT* tab =  qto(&add);//出队Queue_chu(&add);if (tab == NULL){//等于空结束循环break;}//不为空让左右子树入队列//左子树_入队列Queue_ruwei(&add, tab->zuo);//右子树_入队列Queue_ruwei(&add, tab->you);}//循环判断队列,有一个数值不是完全二叉树,都是NULL就是完全二叉树while (!buer(&add)){//取队头BT* app = qto(&add);//出队Queue_chu(&add);//判断如果还有非空节点,返回falseif (app != NULL){Queuexiaoh(&add);return false;}}//循环完,说明队列里都是NULL,是完全二叉树,返回true//队列销毁Queuexiaoh(&add);return true;
}

结果:

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

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

相关文章

每日OJ_牛客_淘宝网店(日期模拟)

目录 牛客_淘宝网店&#xff08;日期模拟&#xff09; 解析代码 牛客_淘宝网店&#xff08;日期模拟&#xff09; 淘宝网店__牛客网 解析代码 这是一个变相的日期计算器。只不过2、3、5、7、11月算1天&#xff0c;其他7个月算2天。 既然是一个变相的日期计算器&#xff0c;那…

基于STM32开发的智能空气质量监测系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化空气质量监测与处理风扇控制与状态显示Wi-Fi通信与远程监控应用场景 家庭和办公室的空气质量监测室内空气净化器的智能控制常见问题及解决方案 常见问题解决方案结论 1. 引言 空气…

单位信息宣传考核投稿方法不对让我尝尽了苦头

自从我担任单位的信息宣传员以来,便深刻体会到“信息宣传”四个字背后的重量。每月的信息宣传考核任务就像一座大山,压在我心头。起初,我像大多数同行一样,习惯于通过电子邮件向各大媒体投稿,但这种方式让我尝尽了苦头。 记得开始尝试通过邮箱投稿时,我满怀信心地将精心准备的文…

web前端之选项卡集合、动态添加类名、动态移除类名、动态添加样式、激活、间距、节流、tabBar

MENU input的checked属性(HtmlStyle)伪元素(HtmlStyleJavaScript)激活类(HtmlStyleJavaScript)vue伪元素 input的checked属性(HtmlStyle) 前言 代码段创建一个使用HTML和CSS实现的标签式内容切换组件。通过选择不同的标签&#xff0c;可以展示相应的内容。 代码段实现一个简洁…

02 tkinter有趣项目-头像制作-界面设计

头像制界面设计 avatar.png 界面 界面分析 背景图片: 顶部中央位置显示一个小孩背着书包的图片。这个图片是程序的背景&#xff0c;占据了大部分的窗口空间。 标题和按钮: 在图片上方&#xff0c;有一个标题栏&#xff0c;显示文本“在线姓氏头像制作”&#xff0c;使用隶书字…

redis面试(二十)读写锁WriteLock

写锁WriteLock 和读锁一样&#xff0c;在这个地方执行自己的lua脚本&#xff0c;我们去看一下 和read没有多大的区别 KEYS[1] anyLock ARGV[1] 30000 ARGV[2] UUID_01:threadId_01:write hget anyLock mode&#xff0c;此时肯定是没有的&#xff0c;因为根本没这个锁 …

“双指针”算法下篇

WeChat_20240806081335 对双指针这一思想在OJ 里面的相关应用&#xff0c;感兴趣的友友们&#xff0c;可以看下此篇博客 https://blog.csdn.net/X_do_myself/article/details/141291451?spm1001.2014.3001.5502 目录 一盛最多水的容器 1题目链接&#xff1a;盛最多水的容器…

音频分割软件有什么?最方便的音频分割软件分享给你

一段长音频就像是一本厚重的百科全书&#xff0c;而音频剪辑师的任务&#xff0c;就是要将这本书拆分成数个章节&#xff0c;每章都有其独立的主题和内容&#xff0c;这非常考验剪辑师们的音频分割技巧。 幸运的是&#xff0c;随着技术的发展&#xff0c;市面上出现了许多优秀…

微信小程序引入全局环境变量

有时候一套代码要在多个小程序appId下使用,其中又有一些数据(文字)需要做区分.可以使用下面的方法 把要配置的数据以export default 形式导出 在app.js中,引入project.config.0.js文件,将导出的数据放在globalData中 在页面目录中,即可利用getApp()方法使用全局变量 也可以放数…

剪辑视频的软件在手,温馨瞬间秒变电影级大片

在现在这个啥都能数字化的年代&#xff0c;家里拍的视频成了咱们记录生活、留下美好回忆的好办法。不过&#xff0c;好多人可能就只是随便拍拍&#xff0c;然后直接发出去&#xff0c;没想过用专业的剪辑视频的软件来搞一搞&#xff0c;让自己的视频更有感觉&#xff0c;看起来…

微服务通信

一、Feign远程调用 Feign是Spring Cloud提供的⼀个声明式的伪Http客户端&#xff0c; 它使得调⽤远程服务就像调⽤本地服务⼀样简单&#xff0c; 只需要创建⼀个接⼝并添加⼀个注解即可。 Nacos很好的兼容了Feign&#xff0c; Feign 默认集了Ribbon&#xff0c; 所以在Nacos下…

vue全局参数

/* eslint-disable no-new */ new Vue({el: #app,router,components: { App },template: <App/>,data:function(){return{wbWinList: [] // 定义的变量&#xff0c;全局参数}}, }) //使用全局参数 // this.$root.backgroundColor 666;其它页面如果想监听改变 //监听全…

polarctf靶场[CRYPTO]显而易见的密码、[CRYPTO]夏多的梦、[CRYPTO]再这么说话我揍你了、[CRYPTO]神秘组织M

[CRYPTO]显而易见的密码 考点&#xff1a;ntlm编码 打开文件&#xff0c;显示内容就是ntlm格式 ntlm解密 在线网站&#xff1a; https://www.cmd5.com/便可得到flag [CRYPTO]夏多的梦 根据题目提示可以猜测为夏多密码 考点&#xff1a;夏多密码 在线加密原理网站&#x…

链表OJ题——链表的回文结构

文章目录 一、题目链接二、解题思路三、解题代码 一、题目链接 链表的回文结构 二、解题思路 三、解题代码

【JAVA基础】类与对象

文章目录 Java类Java对象为什么Java会设计对象Java对象怎么用程序的执行流程 Java类 JAVA类&#xff1a;项目中新建的.java文件就是JAVA类&#xff0c;其中包含代码&#xff0c;通过javac命令编译为二进制.class文件&#xff0c;让计算机读取。类是对象的模板 Java对象 JAVA…

【C++题解】1146. 求S的值

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1146. 求S的值 类型&#xff1a;递归基础、函数 题目描述&#xff1a; 求 S12471116…的值刚好大于等于 5000 时 S 的值。 输入&#xff1a; 无。 输出&#xff1a; 一行&…

原生js中的防抖节流笔记

防抖,单位时间内&#xff0c;频繁触发&#xff0c;只执行最后一次 效果演示 优化前&#xff0c;不断触发&#xff0c;浪费性能 优化后&#xff0c;只在指定时间内触发 演示代码 import debounce from "/node_modules/lodash-es/debounce.js"; const oBox docu…

宿舍管理系统设计与分析

第一章 管理信息系统概述 在人类进入21世纪之际&#xff0c;随着社会的组织化程度以及企业生产的社会化程度越来越高&#xff0c;信息作为一种资源已经和材料、能源并称为现代社会化发展的三大支柱之一。管理信息系统是融科学、信息科学、系统工程以及现代通讯技术、计算机技术…

大数据-92 Spark 集群 SparkRDD 原理 Standalone详解 ShuffleV1V2详解 RDD编程优化

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

ollama+llama3.1 405B 简介

ollamallama3.1 简介 Llama 3.1是一款来自Meta的最新型号&#xff0c;提供8B、70 B和405 B模型。 llama3.1:latestllama3.1:8bllama3.1:70bllama3.1:405bllama3.1:8b-instruct-fp16llama3.1:8b-instruct-q2_Kllama3.1:8b-instruct-q3_K_Sllama3.1:8b-instruct-q3_K_Mllama3.1…