数据结构基础7:二叉树【链式结构】实现和递归思想。

二叉树的链式结构实现

  • 一.二叉树链式结构的实现:
    • 1.前置说明:
      • 1.创建二叉树:
      • 2.二叉树的结构:
    • 2.二叉树的遍历:
      • 1.二叉树的前中后序遍历:
      • 2.内容拓展:
  • 二.二叉树链式(题目)
    • 题目一:计算节点的个数:
      • 方法一:注意事项:
      • 方法二:注意事项:
    • 题目二:计算叶子节点的个数:
      • 方法一:
    • 题目三:求第K层节点的个数:
      • 方法一:
    • 题目四:
      • 方法一:重新定义一个函数:
      • 方法二:(判断左右节点数值和root数值)
    • 题目五:二叉树的最大深度:
      • 方法一:

一.二叉树链式结构的实现:

1.前置说明:

对于一颗二叉树的构建是比较复杂的在刚刚开始了解二叉树的构建的时候。我们可以通过创建多个节点的方式去构建二叉树的结构,直接连接节点的左右节点构建一个二叉树方便去学习。

1.创建二叉树:

struct TreeNode* byNode(TreeNodeData x)
{struct TreeNode* tmp = (struct TreeNode*)malloc(sizeof(struct TreeNode));if (tmp == NULL){perror(tmp);exit(-1);}tmp->val = x;tmp->left = NULL;tmp->right = NULL;return tmp;
}void creatTreeNode()
{//1.构建二叉树:struct TreeNode* n1 = byNode(1);struct TreeNode* n2 = byNode(2);struct TreeNode* n3 = byNode(3);struct TreeNode* n4 = byNode(4);struct TreeNode* n5 = byNode(5);struct TreeNode* n6 = byNode(6);struct TreeNode* n7 = byNode(7);n1->left = n2;n1->right = n3;n2->left = n4;n2->right = n5;n3->left = n6;n3->right = n7;}
int main()
{//1.构建二叉树:creatTreeNode();
}

2.二叉树的结构:

1.需要注意的是上面的代码不是创建二叉树的一个正规方法,后面我的博客是会去涉及到二叉树的一个创建:
1.空树:
2.非空树:
从二叉树的概念可知二叉树是递归构建的所以后面的操作都是基于递归构建的内容。

2.二叉树的遍历:

1.二叉树的前中后序遍历:

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

2.前中后序遍历递归结构遍历:

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

前序遍历:
请添加图片描述

//1.前序
void PreOrder(struct TreeNode* root)
{//1.返回条件:if (root == NULL){printf("NULL ");return ;}//2.进入递归://先printf("%d ", root->val);//左PreOrder(root->left);//右PreOrder(root->right);
}

中序遍历:

//2.中序
void InOrder(struct TreeNode* root)
{//1.返回条件:if (root == NULL){printf("NULL ");return;}//2.进入递归://左PreOrder(root->left);//根:printf("%d ", root->val);//右PreOrder(root->right);
}

后序遍历:

//3.后序
void PostOrder(struct TreeNode* root)
{//1.返回条件:if (root == NULL){printf("NULL ");return;}//2.进入递归://左PreOrder(root->left);//右PreOrder(root->right);//根:printf("%d ", root->val);
}

2.内容拓展:

一.普通二叉树:
1.增删查改是没有意义的:内容上的增删查改对二叉树的结构造成破坏:

二.二叉搜索树(链式结构):
1.AVL树:
2.红黑树:
3.二叉树的oj题目:

请添加图片描述

二.二叉树链式(题目)

题目一:计算节点的个数:

方法一:注意事项:

1.创建在函数里面创建静态局部变量进入递归函数这个变量不会再一次创建:
2.注意root到空的时候的返回值为0:
3.注意不要去创建多个树如果存在多个树去计算节点会导致静态变量数值的问题:

//题目一:计算节点个数://方法一(使用局部静态):
int TreeSize(TN* root)
{//1.返回条件:if (root == NULL){return 0;}//只会在第一次进入函数去定义:static int num = 0;//2.进入递归://1.当前节点:num++;//2.左:TreeSize(root->left);//3.右:TreeSize(root->right);return num;
}

方法二:注意事项:

1.使用分治的思路去每次加上一个当前节点的个数。
2.当节点为空的时候就返回一个0.
3.注意:这个函数可以同时去计算多个树的节点个数:

//方法二(使用分治的思路):
int TreeSize2(TN* root)
{if (root == NULL)return 0;//左节点+右节点return TreeSize2(root->left) + TreeSize2(root->right) + 1;
}

题目二:计算叶子节点的个数:

方法一:

1,叶子节点是没有左子树没有右子树的就是叶子节点:
2.遍历每一个节点,并且判断节点是否是叶子节点:
3.使用分治的思路去计数:

int TreeLeafSize(TN* root)
{//1.只有叶子才返回:if (root->left == NULL && root->right==NULL){return 1;}//2.进入左右子树递归:return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

题目三:求第K层节点的个数:

方法一:

1.函数需要传参数K
2.找根节点的K层就相当于找根节点左子树根的第K-1层:
3.找根节点的K层就相当于找根节点右子树根的第K-1层:
4.进入函数不要多次的进行–,k–不要写在函数中:下一次进入右树的时候就不需要再一次的–了!

//题目三:计算第K层节点个数://方法一:int TreeKSize(TN* root, int k)
{assert(k!=0);//1.如果在k层没有到的情况下到空返回0if (root == NULL){return 0;}//2.当到达K层的时候。if (k == 1){return 1;}//3.没有到达K层并且没有为空的时候就进入递归://3-1:进入不同的栈中只要是同层的就可以保证K值相同:k--;return TreeKSize(root->left, k)+TreeKSize(root->right,k);
}

题目四:

请添加图片描述
题目链接:单值二叉树

方法一:重新定义一个函数:

1.我们前面大部分的操作就是root为空就返回(true)(因为我们是比较数值是否相同所有返回true):
2…如果每一次通过root的数值去判断我们是需要传数值到递归的下一个部分:
3.如果左子树有不相等的就直接返回false(就不需要进入右子树判断):
4.如果左右相等的就继续函数不需要返回(继续进入函数)。

bool isUnivalTreeNode(struct TreeNode* root,int val)
{//1.到空树:if(root==NULL){return true;}//2.数值相同:if(root->val==val){}else if(root->val!=val){return false;}//左子树:if(isUnivalTreeNode(root->left,root->val)){//右子树:return isUnivalTreeNode(root->right,root->val);}return false;
}bool isUnivalTree(struct TreeNode* root){//左子树:if(isUnivalTreeNode(root->left,root->val)){//右子树:return isUnivalTreeNode(root->right,root->val);}return false;
}

方法二:(判断左右节点数值和root数值)

1.如果根为空就返回真:
2.如果左右子树的根节点数值和当前root的数值相同就继续递归进入。
3.如果左右子树中有一个节点数值和root的数值不相同就返回

bool isUnivalTree(struct TreeNode* root){if(root==NULL)return true;//1.这两个思路可以解决一个为空,一个有的情况。//2.解决两个都为空的情况。//3.解决两个都不是空的情况。if(root->left!=NULL && root->left->val != root->val){return false;}if(root->right!=NULL && root->right->val != root->val){return false;}//进入递归:return isUnivalTree(root->left) && isUnivalTree(root->right);
}

题目五:二叉树的最大深度:

方法一:

请添加图片描述

二叉树的深度

1.如果到空就返回0,空不是节点数。
2.每一次比较左右的数的值拿出较大的数值进行+1这个+1就相当加上当前节点。
3.子树的根节点不是空就继续。

int maxDepth(struct TreeNode* root){//1.左为空返回0(空节点不是节点数是一个返回的标志)。//2.右子树不是空就继续进入函数。if(root==NULL)return 0;//2.比较左右子树的返回值取较大的数值:int max=maxDepth(root->left);int max1=maxDepth(root->right); if(max1>max){max=max1;}//在回去的过程中自己也是节点return max+1;
}

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

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

相关文章

yolov7简化网络yaml配置文件

yolov7代码结构简单,效果还好,但是动辄超过70几个模块的配置文件对于想要对网络进行魔改的朋友还是不怎么友好的,使用最小的tiny也有77个模块 代码的整体结构简单,直接将ELAN结构化写成一个类就能像yolov5一样仅仅只有20几个模块&…

【操作系统】进程控制

进程控制:创建新进程,撤销已有进程,实现进程状态转换等。 原语:进程控制用的程序段。执行期间不允许中断,用"关中断"和"开中断"指令(特权指令)实…

Android性能优化之应用瘦身(APK瘦身)

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 目录 一、导读二、概览2.1 apk组成 三、优化方向3.1 源代码3.1.1 代码混…

Dedecms最新版--0day分享分析(二)

前言 接上一篇的Tricks,既然利用远程文件下载方式成为了实现RCE的最好方法,毕竟在执行的时候没有恶意shell文件,恶意木马被存放于远端服务器,那么下文的day就是对远程恶意文件的利用。 环境 下载最新版本: https://…

Kotlin Files Paths write ByteArray writeString写多行BufferedWriter

Kotlin Files Paths write ByteArray writeString写多行BufferedWriter import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardOpenOptionfun main(args: Array<String>) {val filePath "./myfile.txt"val path Paths.get(…

ModuleNotFoundError: No module named ‘gevent‘

1、先确定pip版本&#xff1a; pip3 list: 看到没有gevent包 如果pip版本不是最新版可以使用命令python -m pip install --upgrade pip进行更新&#xff0c; 2、安装 pip3 install gevent 安装完成

Java密码学之加解密

前篇&#xff1a;Java密码学之数字签名_东皋长歌的博客-CSDN博客 日常开发中用的比较多的功能点&#xff0c;加解密数据&#xff0c;用Java实现也是很快很实用。 下面记录一下加解密数据的过程。 1&#xff0c;创建密钥对生成器 KeyPairGenerator keyPairGen KeyPairGener…

第29章_瑞萨MCU零基础入门系列教程之改进型环形缓冲区

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

Qt应用开发(基础篇)——普通按钮类 QPushButton QCommandLinkButton

一、前言 QPushButton类继承于QAbstractButton&#xff0c;是一个命令按钮的小部件。 按钮基类 QAbstractButton 按钮或者命令按钮是所有图形界面框架最常见的部件&#xff0c;当按下按钮的时候触发命令、执行某些操作或者回答一个问题&#xff0c;典型的按钮有OK&#xff0c;A…

F. Magic Will Save the World(DP)

Problem - F - Codeforces 黑暗势力的传送门在世界边界打开了&#xff0c;现在整个世界都面临着可怕的威胁。为了关闭传送门并拯救世界&#xff0c;你需要一个接一个地击败n个从传送门中出现的怪物。 只有女巫Vika能够应对这个威胁。她有两个魔法力量——水之魔法和火之魔法。…

Java学习之--类和对象

&#x1f495;粗缯大布裹生涯&#xff0c;腹有诗书气自华&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java学习之--类和对象 类和对象 类的实例化&#xff1a; 1.什么叫做类的实例化 利用类创建一个具体的对象就叫做类的实例化&#xff01; 当我们创建了…

数据在内存中的存储——练习3

题目&#xff1a; 3.1 #include <stdio.h> int main() {char a -128;printf("%u\n",a);return 0; }3.2 #include <stdio.h> int main() {char a 128;printf("%u\n",a);return 0; }思路分析&#xff1a; 首先二者极其相似%u是无符号格式进行…