数据结构(初阶6)---二叉树(遍历——递归的艺术)(详解)

二叉树的遍历与练习

  • 一.二叉树的基本遍历形式
    • 1.前序遍历(深度优先遍历)
    • 2.中序遍历(深度优先遍历)
    • 3.后序遍历(深度优先遍历)
    • 4.层序遍历!!(广度优先遍历)
  • 二.二叉树的leetcode小练习
    • 1.判断平衡二叉树
      • 1)正常解法
      • 2)优化解法
    • 2.对称二叉树

通过上一篇文章,我们初识了我们的二叉树
二叉树初识
那么接下来我们就要深入去理解二叉树的部分知识了,显然这只是在二叉树家族中迈出的一小步qwq,入门。

一.二叉树的基本遍历形式

我们先建立一棵伪树,方便我们后续的使用:请添加图片描述

int main()
{
	BinaryTree p1;
	BinaryTree p2;
	BinaryTree p3;
	BinaryTree p4;
	BinaryTree p5;
	BinaryTree p6;
	p1.left = &p2;
	p1.right = &p3;
	p2.left = NULL;
	p2.right = &p4;
	p3.left = &p5;
	p3.right = NULL;
	p4.left = NULL;
	p4.right = &p6;
	p6.left = NULL;
	p6.right = NULL;
	p5.left = NULL;
	p5.right = NULL;
	p1.val = 'A';
	p2.val = 'B';
	p3.val = 'C';
	p4.val = 'D';
	p5.val = 'E';
	p6.val = 'F';
}

1.前序遍历(深度优先遍历)

前序遍历的本质,就是根节点->左孩子->右孩子。并且通过递归调用的方式去实现。
请添加图片描述

void treefront(BinaryTree* p)//前序遍历
{
	if (p == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%c ", p->val);
	treefront(p->left);
	treefront(p->right);

}

2.中序遍历(深度优先遍历)

同理,中序遍历的本质就是左孩子->根节点->右孩子
如:
请添加图片描述

void treemid(BinaryTree* p)//中序遍历
{
	if (p == NULL)
	{
		printf("NULL ");
		return;
	}
	treemid(p->left);
	printf("%c ", p->val);
	treemid(p->right);

}

3.后序遍历(深度优先遍历)

同理,后序遍历的本质就是:左孩子->右孩子->根节点
如:
请添加图片描述

void treebehind(BinaryTree* p)//后序遍历
{
	if (p == NULL)
	{
		printf("NULL ");
		return;
	}
	treebehind(p->left);
	treebehind(p->right);
	printf("%c ", p->val);
}

4.层序遍历!!(广度优先遍历)

层序遍历与以上三种遍历方式完全不同,他没有使用递归的思想,而是去使用了迭代的方法:
请添加图片描述
这里我们将使用我们先前学到的循环队列的数据结构去完成二叉树的层序遍历
逻辑如下:
运用队列的先进先出的特点
1.我们先塞入第一个根节点,
2.我们取出队列排头的节点的时候,自动往队列里面添加两个他的儿子节点
3.当队列里面为空的时候,我们就完成了一次层序遍历
请添加图片描述
接下来我们进行代码实现:
1.伪树

int main()
{
	BinaryTree p1;
	BinaryTree p2;
	BinaryTree p3;
	BinaryTree p4;
	BinaryTree p5;
	BinaryTree p6;
	p1.left = &p2;
	p1.right = &p3;
	p2.left = NULL;
	p2.right = &p4;
	p3.left = &p5;
	p3.right = NULL;
	p4.left = NULL;
	p4.right = &p6;
	p6.left = NULL;
	p6.right = NULL;
	p5.left = NULL;
	p5.right = NULL;
	p1.val = 'A';
	p2.val = 'B';
	p3.val = 'C';
	p4.val = 'D';
	p5.val = 'E';
	p6.val = 'F';
}

2.层序遍历

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef BinaryTree* QueueDataType;
typedef struct CirQueue
{
	QueueDataType* q;
	int front;
	int rear;
	int capacity;
}CirQueue;


QueueDataType Cirqueuefront(CirQueue* p1)
{
	return *((p1->q)+(p1->front));
}

CirQueue* CirQueueCreate(CirQueue* p,size_t x)
{
	p = (CirQueue*)malloc(sizeof(CirQueue));
	p->q = (QueueDataType*)(malloc(sizeof(QueueDataType) * x));
	p->capacity = x;
	p->front = 0;
	p->rear = 0;
}
int isCirQueueEmpty(CirQueue* p)
{
	if (p->front == p->rear)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int isCirQueueFull(CirQueue* p)
{
	if ((p->rear+1) % p->capacity == p->front)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
void CirQueuePop(CirQueue* p)
{
	if (!isCirQueueEmpty(p))
	{
		p->front=(p->front+1)%p->capacity;
	}
	else
	{
		return;
	}
}
void CirQueuePush(CirQueue* p,QueueDataType x)
{
	if (isCirQueueFull(p))
	{
		return;
	}
	else
	{
		*(p->q + p->rear) = x;
		p->rear = (p->rear + 1) % p->capacity;
	}
}

void treeseq(BinaryTree* p)//层序遍历
{
	CirQueue* que=NULL;
	que = CirQueueCreate(que, 20);
	CirQueuePush(que, p);
	while (!isCirQueueEmpty(que))
	{
		if (Cirqueuefront(que) != NULL)
		{
			printf("%c ", Cirqueuefront(que)->val);
			CirQueuePush(que, Cirqueuefront(que)->left);
			CirQueuePush(que, Cirqueuefront(que)->right);
		}
		else
		{
			printf("NULL ");
		}
		CirQueuePop(que);
	}
}

在这里插入图片描述

二.二叉树的leetcode小练习

1.判断平衡二叉树

在这里插入图片描述
平衡二叉树:当二叉树的每一个节点的两个子树的深度的差的绝对值小于1,则称为平衡二叉树。

1)正常解法

1.先创造求深度函数

int depthtree(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    int leftdepth=depthtree(root->left);
    int rightdepth=depthtree(root->right);
    return 1+(leftdepth>rightdepth?leftdepth:rightdepth);
}

再通过分解子问题
求大树是否为平衡二叉树,我们先求解两个子树是不是平衡二叉树

bool isBalanced(struct TreeNode* root) {
    if(root==NULL)
    {
        return true;
    }
    int left=depthtree(root->left);
    int right=depthtree(root->right);
    bool x=(left-right<=1)&&(left-right>=-1);
    if(!x)
    {
        return false;
    }
    return isBalanced(root->left)&&isBalanced(root->right);
}

2)优化解法

刚刚的那种解法是一种低效的解法,通过前序遍历我们进行了很多次重复的计算。
所以我们考虑一下,是否可以使用后序遍历,
先快速来到底部,从底部向上走,而每一次的树的深度就可以直接将当前子树的高度++即可

bool _isBalanced(struct TreeNode* root,int* pdepth)
{
    
    if(root==NULL)
    {
        return true;
    }
    int depth_left=0;
    int depth_right=0;
    if(!_isBalanced(root->left,&depth_left))
    {
        return false;
    }
    if(!_isBalanced(root->right,&depth_right))
    {
        return false;
    }
    if(abs(depth_right-depth_left)>1)
    {
        return false;
    }
    *pdepth=1+(depth_right>depth_left?depth_right:depth_left);
    return true;
}
bool isBalanced(struct TreeNode* root) {
    int depth=0;
    return _isBalanced(root,&depth);
}

在这里插入图片描述

这样子我们只需要遍历n次,时间复杂度O(n)即可解决问题

2.对称二叉树

在这里插入图片描述
通过相反的遍历比较,可以得出是否为二叉树

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

在这里插入图片描述

ps:创作不易,恳请留一个赞吧

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

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

相关文章

k8s集群增加nfs-subdir-external-provisioner存储类

文章目录 前言一、版本信息二、本机安装nfs组件包三、下载nfs-subdir-external-provisioner配置文件并进行配置1.下载文件2.修改配置 三、进行部署备注&#xff1a;关于镜像无法拉取问题的处理 前言 手里的一台服务器搭建一个单点的k8s集群&#xff0c;然后在本机上使用nfs-su…

C++ For Hot100

数组&#xff1a;数组是存放在连续内存空间上的相同类型数据的集合。 1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> v;for(int i 0;i<nums.size…

高校宿舍节能用电现状及智慧监管平台构建

0 引言 在节能减排的大背景下&#xff0c;高校通过精细化宿舍用电管理&#xff0c;提升师生的节能节电意识等举措&#xff0c;能够显著提高电能资源的使用效率&#xff0c;并有效预防火灾等安全事故&#xff0c;确保师生的人身安全。因此&#xff0c;当前亟需加强对智慧监管平…

Spring Boot英语知识网站:开发策略

5系统详细实现 5.1 管理员模块的实现 5.1.1 用户信息管理 英语知识应用网站的系统管理员可以对用户信息添加修改删除以及查询操作。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.1.2 在线学习管理 系统管理员可以对在线学习信息进行添加&#xff0c;修改&#xff0…

Jmeter中的前置处理器

5&#xff09;前置处理器 1--JSR223 PreProcessor 功能特点 自定义数据处理&#xff1a;使用脚本语言处理请求数据&#xff0c;实现高度定制化的数据处理和生成。动态数据生成&#xff1a;在请求发送前生成动态数据&#xff0c;如随机数、时间戳等。变量设置&#xff1a;设置…

华为鸿蒙内核成为HarmonyOS NEXT流畅安全新基座

HDC2024华为重磅发布全自研操作系统内核—鸿蒙内核&#xff0c;鸿蒙内核替换Linux内核成为HarmonyOS NEXT稳定流畅新基座。鸿蒙内核具备更弹性、更流畅、更安全三大特征&#xff0c;性能超越Linux内核10.7%。 鸿蒙内核更弹性&#xff1a;元OS架构&#xff0c;性能安全双收益 万…

EG3D: Efficient Geometry-aware 3D Generative Adversarial Networks 学习笔记

1 Contributions 混合显式-隐式网络架构&#xff1a;提出了一种 Tri-plane 的3D表征方法&#xff0c;结合显式体素网格与隐式解码器的优点 速度快&#xff0c;内存效率高&#xff1b; 支持高分辨率生成&#xff0c;保持3D表征的灵活性和表达能力。与纯显式或隐式方法相比&#…

【数据结构OJ】相交链表问题,求相交链表的相交第一个交点

题目如下&#xff08;题目来源力扣&#xff09;&#xff1a; 个人解题思路&#xff1a; 运用双指针&#xff0c;第一次遍历先一起走&#xff0c;当一个走到尾时开始计数&#xff0c;等另一个指针也走到尾时记录下两个指针的路程差&#xff0c;同时比对两个指针指向的地址是否相…

【C语言】指针与数组的例题详解:深入分析与高级用法

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目一详细分析与解答代码逐步解析 &#x1f4af;进一步优化和拓展1. 指针与数组的关系2. 指针运算的注意事项3. 常见的错误和陷阱4. 拓展&#xff1a;指针操作的应用场…

【Java】ArrayList与LinkedList详解!!!

目录 一&#x1f31e;、List 1&#x1f345;.什么是List&#xff1f; 2&#x1f345;.List中的常用方法 二&#x1f31e;、ArrayList 1&#x1f34d;.什么是ArrayList? 2&#x1f34d;.ArrayList的实例化 3&#x1f34d;.ArrayList的使用 4&#x1f34d;.ArrayList的遍…

【SQL Server】华中农业大学空间数据库实验报告 实验六 视图

1.实验目的 通过课堂理论学习与实验课的实际操作&#xff0c;充分理解视图的相关概念&#xff0c;作用&#xff0c;以及特点&#xff0c;视图中定义的是对一个或多个基本表的查询语句&#xff0c;其本身并不保存数据&#xff0c;所有的数据都存储在数据库的表中&#xff0c;因…

javaweb-day01-html和css初识

html:超文本标记语言 CSS&#xff1a;层叠样式表 1.html实现新浪新闻页面 1.1 标题排版 效果图&#xff1a; 1.2 标题颜色样式 1.3 标签内颜色样式 1.4设置超链接 1.5 正文排版 1.6 页面布局–盒子 &#xff08;1&#xff09;盒子模型 &#xff08;2&#xff09;页面布局…

【Android】webview常用方法和使用

文章目录 前言一、常见用法二、基础属性webView的常用方法WebViewClient的常用方法WebChromeClient的常用方法WebSettings的相关方法 三、加载流程和事件回调四、webview和JS之间的互相调用总结 五、参考链接 前言 最近项目又用到了webview&#xff0c;在回顾复习一次webview相…

【微服务架构】Kubernetes与Docker在微服务架构中的最佳实践(详尽教程)

文章目录 什么是微服务架构Docker在微服务中的应用Docker基础Docker的核心组件 Docker在微服务中的优势 Kubernetes在微服务中的应用Kubernetes基础Kubernetes的核心组件 Kubernetes在微服务中的优势 Kubernetes与Docker的集成最佳实践容器化微服务服务发现与负载均衡自动化部署…

深入了解JDK动态代理

什么是JDK动态代理 &#xff08;有动态代理&#xff0c;就有静态代理&#xff0c;参见&#xff1a;多线程03--静态代理模式_runnable接口静态代理模式-CSDN博客&#xff09; JDK动态代理是Java提供的一种动态生成代理对象的机制&#xff0c;允许在运行时创建一个实现了指定接口…

C#基础56-60

56.字符数组x中存有任意一串字符&#xff1b;串中的所有小写字母改写成大写字母&#xff0c;如果是大写字母改为小写字母&#xff0c;其他字符不变。最后把已处理的字符串仍重新存入字符数组x中&#xff0c;最后调用函数把结果输出到控制台中。 57.求出100以上1000以内所有个位…

华为IPD流程管理体系L1至L5最佳实践-解读

该文档主要介绍了华为IPD流程管理体系&#xff0c;包括流程体系架构、流程框架实施方法、各业务流程框架示例以及相关案例等内容&#xff0c;旨在帮助企业建立高效、规范的流程管理体系&#xff0c;实现业务的持续优化和发展。具体内容如下&#xff1a; 1. 华为流程体系概述 -…

Edge浏览器保留数据,无损降级退回老版本+禁止更新教程(适用于Chrome)

3 个月前阿虚就已经写文章告警过大家&#xff0c;Chromium 内核的浏览器将在 127 以上版本开始限制仍在使用 Manifest V2 规范的扩展&#xff1a;https://mp.weixin.qq.com/s/v1gINxg5vMh86kdOOmqc6A 像是 IDM、油猴脚本管理器、uBblock 等扩展都会受到影响&#xff0c;后续将无…

DevOps引领数字化转型新趋势

DevOps帮助数字化转型 在数字化转型的大潮中&#xff0c;DevOps作为一种文化、运动和实践&#xff0c;已经成为推动企业快速适应市场变化、提高竞争力的关键因素。DevOps的核心在于打破开发&#xff08;Development&#xff09;和运维&#xff08;Operations&#xff09;之间的…

ctfshow

1,web21 Basic认证采用Base64加密方式&#xff0c;Base64解码字符串发现是 用户名:密码 的格式进行Base64编码。 密码shark63 2,web22 用 子域名扫描器 扫出flag.ctf.show拿到flag&#xff0c;但这个域名已经没了所以就直接交的官方提供的flag。 3,web23 这段PHP代码是一个简单…