数据结构基础8:二叉树oj+层序遍历。

二叉树oj+层序遍历

  • 题目一:二叉树的销毁:
    • 方法一:前序遍历:
    • 方法二:后序遍历:
  • 题目二:二叉树查找值为x的节点
    • 方法一:
    • 方法二:
    • 方法三:
  • 题目三:层序遍历:
    • 方法一:
  • 题目四:相同的树:
    • 方法一:
  • 题目五:对称二叉树:
    • 方法一:
  • 题目五:另一颗树的子树:
    • 方法一:
  • 题目六:二叉树的前序遍历:
    • 方法一:
    • 拓展:
  • 题目七:翻转二叉树:
    • 方法一:

题目一:二叉树的销毁:

方法一:前序遍历:

1.前序遍历需要先销毁根节点:
2.在销毁节点之前需要保存左右节点:
3.通过保存的节点的地址再一次进入函数进行递归:
4.总结:相当于从上向下遍历:

//2.销毁://方法一:(先序的销毁)保存根节点的左右节点的地址销毁自己。
void BeforeTreeDestory(struct TreeNode* root)
{//1.根节点为空:if (root == NULL)return;//2.保存左右节点的根节点:struct TreeNode* left = root->left;struct TreeNode* right = root->right;free(root);//3.进入递归:BeforeTreeDestory(left);BeforeTreeDestory(right);
}

方法二:后序遍历:

1.左子树右子树根,左子树又有左子树右子树根。
2.到走到返回的时候,这个时候左和右的走完回来了就可以销毁当前树的根
3.总结:这是一个先到最然后再去从下到上的销毁。
4.好处:不需要像前序遍历去保存左右节点的地址再一次进入递归(在返回的时候就可以销毁节点)

//方法二:(后序遍历)先进入左右子树然后这是一种从下到上的销毁:
void EndTreeDestory(struct TreeNode* root)
{if (root = NULL)return;//进入左右子树回来才销毁:EndTreeDestory(root->left);EndTreeDestory(root->right);//销毁根节点:free(root);
}

题目二:二叉树查找值为x的节点

方法一:

1.使用先序遍历;
///
2.返回的条件:
1.根为空就返回说明没有找到:
2.找到值为x的节点返回节点的地址。
3.注意:数值不相同不需要返回说明还没有找到不需要返回:


3.返回的是节点的地址如果使用&& 和 || 逻辑运算符是不会返回地址的是只会返回0,1的这是需要注意的。
4.递归注意:因为我们需要返回节点的地址是需要从return一个节点之后从递归开辟的栈帧空间中带回来:

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{//1.根节点为空:if (root == NULL)return NULL;//2.数值相同(找到值为X的节点不需要继续往下找了)://只有数值相同的根节点才会被返回回来:if (root->val == x)return root;//3.进入左右子树,这个数值到了非常深才可以被找到:struct TreeNode* tmp1 = BinaryTreeFind(root->left, x);if (tmp1 != NULL)return tmp1;struct TreeNode* tmp2 = BinaryTreeFind(root->right, x);if (tmp2 != NULL)return tmp2;//左右子树都没有找到的情况:return NULL;}

方法二:

1.在方法一的基础上进行优化:
2.你会发现根据上面的两个判断:
1.如果根节点为空就返回NULL
2.如果数据相同就返回节点
3.如果这颗树没有数值相同的节点就返回NULL
总结:不需要对函数返回值进行判空处理直接让返回值作为判断条件是空就不会进入语句里面,如果不是空就一定是数值相等的节点的地址。返回地址就没有问题。

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{//1.根节点为空:if (root == NULL)return NULL;//2.数值相同(找到值为X的节点不需要继续往下找了)://只有数值相同的根节点才会被返回回来:if (root->val == x)return root;//方法二:struct TreeNode* tmp = NULL;tmp = BinaryTreeFind(root->left, x);if (tmp)return tmp;tmp = BinaryTreeFind(root->right, x);if (tmp)return tmp;return NULL;
}

方法三:

1.如果左子树没有节点的话就直接返回右子树的函数返回值就可以:
2.右子树中无非只有两个情况:
1.有数据返回固定的节点地址:
2.找到底没有数据返回NULL
所以右子树的返回就不需要去判断:

struct TreeNode* BinaryTreeFind(struct TreeNode* root, TreeNodeData x)
{//1.根节点为空:if (root == NULL)return NULL;//2.数值相同(找到值为X的节点不需要继续往下找了)://只有数值相同的根节点才会被返回回来:if (root->val == x)return root;//方法三:struct TreeNode* tmp = NULL;tmp = BinaryTreeFind(root->left, x);if (tmp)return tmp;return BinaryTreeFind(root->right, x);//1.返回值需要接受,层层接受。//2.防止返回值为空。//3.或和与的运算符返回的值是0/1 地址丢失!
}

题目三:层序遍历:

方法一:

1.层序顾名思义就是一层一层的去遍历数据:
2.可以使用队列的数据结构保存数据:、
3.让根带左右子树
4.在根节点被pop之前top出节点并且访问数值去打印并且将左右子树的根节点入队列:
5.当队列为空说明二叉树的所有节点已经被层序遍历完全了:

//4.层序遍历: 队列存储:
void LevelOrder(struct TreeNode* root)
{assert(root != NULL);//初始化队列:Que pQ;QueueInit(&pQ);//入根节点:QueuePush(&pQ, root);while (!QueueEmpty(&pQ)){//获取堆头的数据QueueDatatype top = QueueFront(&pQ);//打印队头数据:if(top!=NULL)printf("%d ", top->val);//出去之前把孩子带进来(不需要递归的!!!)if(top->left!=NULL)QueuePush(&pQ, top->left);if(top->right!=NULL)QueuePush(&pQ, top->right);//pop数据:QueuePop(&pQ);}//销毁队列:QueueDestor(&pQ);}

题目四:相同的树:

请添加图片描述
相同的树:题目链接

方法一:

bool isSameTree(struct TreeNode* p, struct TreeNode* q){//1.如果两个都是空节点说明相同if(p==NULL && q==NULL)return true;//2.经过1的判断p,q中至少有一个不是空是有数值的://这样的情况如果进入一定是false。if(p==NULL || q==NULL)return false;//3.经过1,2的判断到这里一定满足两个节点都不是空节点。//两个情况://1.两个节点的值不相同返回false//2.两个节点的值相同但是还没有找完所有的节点所以继续进入递归寻找:if(p->val != q->val)return false;//4.如果两个 左子树对应已经有不相同的了就不需要进入右树了:return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}

题目五:对称二叉树:

方法一:

1.这个题目和上面那个有一点点相似,这里比较一颗树的左右子树是否对称。上一个题目是比较直接给好的两个数的是否相同:
2.我们可以写一个子函数去传这一颗树的左右子树的根节点作为新的两颗树的根节点判断是否对称:
3.判断对称是判断相反的节点值是否相同(不同于判断俩颗树的相同相对位置的值是否相同)

请添加图片描述
对称二叉树:题目链接

bool isdouSymmetric(struct TreeNode* p ,struct TreeNode* q)
{//两个都为空,走到底了!if(p==NULL && q==NULL)return true;//一个空,一个不是空:if(p==NULL || q==NULL)return false;//两个都不是空:Lif(p->val != q->val)return false;//第一个是判断左数的左和右树的右的对称://第二个是判断左数的右和右树的左的对称return isdouSymmetric(p->left , q->right)&&isdouSymmetric( p->right ,q->left );
}bool isSymmetric(struct TreeNode* root){//写一个子函数进入左右子树:return isdouSymmetric(root->left,root->right);
}

题目五:另一颗树的子树:

在这里插入图片描述
另一颗树的子树:题目链接

方法一:

1.有两个树一个树是父母。一颗树是儿子在父母中有可能找到儿子。
2.注意二子要和父母中的这个树完全相同直到后面都为空了不能说一部分相同后面还有一部分不相同的两个树:
3.我们前面写过判断两个数是否相同的函数现在找到父母这个数子树中的一个根和待比较树的根节点的相同就有可能存在相同的子树
4.当父母这个数到空就说明这颗子树没有相同的树包括没有数值的相等:
5.原函数使用 || 连接的好处是如果左树中有相同的子树并且返回了true就不需要再加入右树去判断,如果左树中没有相同的树还可以到右树中去寻找。只有左右都为false才返回false表示不存在相同的子树

bool isSameTree(struct TreeNode* p, struct TreeNode* q){//1.两个空数if(q==NULL && p==NULL){return true;}//2.一个为空 另一个必须不为空:if(p==NULL || q==NULL){return false;}//3.两个数值一开始就不相等: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){//1.没有子树返回falseif(root==NULL)return false;//2.根节点的值相同有可能是相同子树的根节点:if(root->val == subRoot->val){if(isSameTree(root,subRoot)){return true;}}//进入递归(先序遍历):return isSubtree(root->left , subRoot)|| isSubtree(root->right , subRoot);
}

题目六:二叉树的前序遍历:

在这里插入图片描述
前序遍历:题目链接

方法一:

1.分析一下函数的参数和返回值:
1.返回一个数组的首地址(已经保存和前序遍历的数据)!
2.需要在堆区开辟空间这样才可以在外面找到这个数组的内容:
2.returnsize 返回数组的大小帮助外面去遍历数据:
3.使用计算节点个数的函数:

int TreeSize(struct TreeNode* root)
{return root==NULL? 0: TreeSize(root->left)+TreeSize(root->right)+1;
}void Traversal(struct TreeNode* root , int* tmp , int* i)
{if(root==NULL)return;tmp[*i]=root->val;(*i)++;Traversal(root->left , tmp , i);Traversal(root->right, tmp , i);
}int* preorderTraversal(struct TreeNode* root, int* returnSize){//1.开辟数组,返回顺序表长度int n=TreeSize(root);*returnSize = n;int* tmp=(int*)malloc(sizeof(int)*n);//2.给顺序表中添加内容:int i=0;Traversal(root , tmp , &i);return tmp;
}

拓展:

中序遍历:题目链接
后序遍历:题目链接

题目七:翻转二叉树:

请添加图片描述
翻转二叉树:题目链接

方法一:

1.不需要考虑左右子树为空的情况.
2.直接进行交换,下一次递归进入函数如果为空就会返回用了下一次函数判断当前为空的处理!
3.翻转是翻转每一颗树左右子树的根节点的情况!

请添加图片描述

void convert(struct TreeNode* root)
{if(root==NULL)return;struct TreeNode* tmp=NULL;tmp=root->left;root->left=root->right;root->right=tmp;convert(root->left);convert(root->right);
}struct TreeNode* invertTree(struct TreeNode* root){if(root==NULL)return root;convert(root);return root;
}

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

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

相关文章

二叉树(堆)

堆的性质: 堆中某个节点的值总是不大于或不小于其父节点的值; 堆总是一棵完全二叉树。 大堆:任何父亲≥孩子 小堆:任何父亲≤孩子 接下来,我们要做的便是对堆进行增加和删除: 首先是增加操作&#xff0c…

leetcode 673. 最长递增子序列的个数

2023.9.13 做本题之前先复习一下 最长递增子序列 ,在此基础上还要加个count数组,用于记录当前下标 最长递增子序列的个数。 本题还是有些难度,日后再来二刷。

每日一题~中序后序遍历构造二叉树

原题链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) 题目描述: 思路分析: 后序遍历分析图 中序遍历分析图 不难看出后序遍历的结果中的最后一个元素就是根节点,倒数第二个元素则是根节点的…

Electron和vue3集成(推荐仅用于开发)

本篇我们仅实现Electron和vue3通过先运行起vue3项目,再将vue3的url地址交由Electron打开的方案,仅由Electron在vue3项目上套一层壳来达到脱离本机浏览器运行目的 1、参考快速上手 | Vue.js搭建起vue3初始项目 npm install -g vue npm install -g vue/c…

深入理解Linux网络笔记(一):内核是如何接收网络包的

本文为《深入理解Linux网络》学习笔记,使用的Linux源码版本是3.10,网卡驱动是Intel的igb网卡驱动 Linux源码在线阅读:https://elixir.bootlin.com/linux/v3.10/source 1、内核是如何接收网络包的 1)、Linux网络收包总览 在TCP/I…

手刻 Deep Learning -第壹章 -PyTorch教学-激励函数与感知机入门(上)

一、前言 本文接续前篇教学 Pytorch 与线性回归 ,本文着重在 Activation Function ( 中文称 激励函数 ),我们会介绍激励函数 (也有人称 激活函数? 激发函数? ) 为什么会有用&#xf…

vim,emacs,verilog-mode这几个到底是啥关系?

vim:不多说了被各类coder誉为地表最强最好用的编辑器;gvim,gui vim的意思; emacs:也是一个编辑器,类似vscode; vim在使用的时候为了增强其功能,有好多好多插件,都是以.…

差分方程模型:蛛网模型

在完全竞争的市场经济中,一个时期某种消费品如猪肉的上市量远远大于需求量,由于销售不畅导致价格下降,生产者发现养猪赔钱,于是转而经营其它农副产品。过一段时间猪肉上市量就会下降,此时供不应求导致价格上涨&#xf…

【Linux】常用工具(上)

Linux 常用工具 一、Linux 软件包管理器 yum1. 软件包2. 查看软件包3. 安装/卸载软件4. yum 其他指令的功能 二、Linux 编辑器 - vim 使用1. vim 的基本概念2. vim 的基本操作(1)光标移动(命令模式)(2)光标…

防雷接地,综合防雷综合解决方案

雷电是一种自然现象,也是一种灾害。雷电对人类社会的影响是巨大的,不仅会造成人员伤亡和财产损失,还会对电力、通信、交通、石油、化工等重要行业的设备和系统造成严重的破坏。因此,防雷减灾是一项重要的公共安全工作。 随着科技…

C++QT day7

仿照vector手动实现自己的myVector&#xff0c;最主要实现二倍扩容功能 #include <iostream>using namespace std;template<typename T> class my_vector {int size;//可存储的容量大小int num;//当前存储的元素个数T* data;//存储数据的空间地址public://无参构造…

【开发】视频监控平台EasyCVR分组批量绑定/取消通道功能的后端代码设计逻辑介绍

视频监控平台/视频存储/视频分析平台EasyCVR基于云边端一体化管理&#xff0c;可支持视频实时监控、云端录像、云存储、磁盘阵列存储、回放与检索、智能告警、平台级联等功能。安防监控平台在线下场景中应用广泛&#xff0c;包括智慧工地、智慧工厂、智慧校园、智慧社区等等。 …