当前位置: 首页 > news >正文

五华网站建设wordpress视频商店

五华网站建设,wordpress视频商店,电子网站建设考试,建企业版网站多久​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 递归遍历前序遍历中序遍历后…

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 递归遍历
    • 前序遍历
    • 中序遍历
    • 后序遍历
  • 非递归遍历
    • 前序遍历
    • 后序遍历
    • 中序遍历
    • 标记迭代法
  • 总结:

这一期讲树这个数据结构的相关知识

首先我们要明白树的两种通用遍历分别是深度优先搜索,和广度优先搜索。这里我们介绍深度优先搜索的三种表现形式:前序遍历,中序遍历和后序遍历。这三种搜索方式可以用递归法或者迭代法表示出来。事实上,很多递归能写出来的代码,大都可以使用迭代法表示出来。

递归遍历

前序遍历

class Solution 
{
public:
vector<int>result;
void dfs(TreeNode* root)
{if(root)result.push_back(root->val);if(root)dfs(root->left);if(root)dfs(root->right);
}vector<int> preorderTraversal(TreeNode* root) {if(root==nullptr)return result;dfs(root);return result;}
};

前序遍历的规则是“中左右“,即先遍历树的中间节点,再分别遍历左右两子树,并在其遍历左右两子树时仍然遵循此规则。所以我们可以容易的理解dfs代码部分先将中间节点保存后,分别进行左子树和右子树的递归。

中序遍历和后序遍历的递归代码,都和前序遍历差不多,只是略微调整一下进入子树的时机而已,下面直接给出代码。

中序遍历

class Solution 
{
public:void dfs(TreeNode* root,vector<int>& result){if(root==nullptr)return ;dfs(root->left,result);result.push_back(root->val);dfs(root->right,result);}vector<int> inorderTraversal(TreeNode* root) {vector<int>result;dfs(root,result);return result;}
};

后序遍历

class Solution 
{
public:void dfs(TreeNode* root,vector<int>& result){if(root==nullptr)return ;dfs(root->left,result);dfs(root->right,result);result.push_back(root->val);}vector<int> inorderTraversal(TreeNode* root) {vector<int>result;dfs(root,result);return result;}
};

说完了递归遍历,我们再来看看非递归遍历

非递归遍历

非递归遍历中的迭代遍历,前后序的代码是差不多的,但是中序遍历有很大差别

前序遍历

先说前序遍历的迭代,思路是用一个栈来模拟递归的操作

为什么我们会想到使用栈来模拟呢?

因为递归实际上就是编译器将函数各参数放入递归内部,返回时再将其弹出,所以我们用一个栈来模拟递归操作,是再合适不过的。我们写一个循环判断栈中是否为空,为空则说明没有元素要处理了,那么循环内的逻辑就是先创立一个临时的节点指针指向当前栈口处元素,先判断其是否为空,为空不能操作,否则会操作空指针。
不为空时我们先将遍历到的节点直接放入数组中,因为前序遍历是先处理中间节点,这之后我们按照先放入右节点再放入左节点的规律来使节点指针向后遍历。

这是为什么呢?

原因在于栈的独特定义,我们要先放入右节点再放入左节点,才能在下一步时候先处理左节点!以下代码

class Solution 
{
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> s;vector<int>result;if(root==nullptr)return result;s.push(root);//加入的是节点而并非节点对应的值,这里要尤其注意while(!s.empty()){TreeNode* node=s.top();s.pop();if(node)result.push_back(node->val);else continue;s.push(node->right);s.push(node->left);}return result;}
};

后序遍历

后序遍历思路很类似,需要注意的是后序遍历的情况为”左右中“,我们可以按照前序遍历的代码模板将前序遍历的压栈操作改为先放入左节点再放入右节点,这样它对应的原本遍历方法是中右左,当全部遍历完成之后,我们将数组部分反转,即可得到后序遍历。

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*>s;vector<int>result;if(root==nullptr)return result;s.push(root);while(!s.empty()){TreeNode*node=s.top();s.pop();if(node)result.push_back(node->val);else continue;s.push(node->left);s.push(node->right);}reverse(result.begin(),result.end());return result;}
};

这里可以看出,后序和前序的代码差别不大,也就是改了入栈的顺序,和反转了一下数组。

中序遍历

接着,我们再来看看中序遍历。

中序遍历的思路是:我们需要建立一个指针来存储各节点,然后我们将它们放入栈内,我们先一直向二叉树的左节点遍历直到无法继续为止,弹出栈顶元素,此时栈顶元素即为我们要找的元素,为什么呢?

因为我们是一直向左走,直到无法再向左走,弹出的那个元素,此时就是这个子树的中间节点(由于没有左节点)直接放入答案数组内,再遍历这个节点的右节点(不要忘记将其压入栈内),如果它有左节点接着遍历,如果它没有,那么就直接弹出,重复上述操作。

为什么中序遍历不能像前后序那样只调整位置呢?
拿前序遍历举例它是先遍历的中间节点也是先处理的中间节点,后序的代码前面思路也是如此,只是后面有调整位置,换句话说,是此时遍历的节点正是我们此时要处理的数据!

那我们在遍历中序时候可以先遍历左边子树达成一样的逻辑吗?答案肯定是否定的,因为我们一开始只有root这个节点,而它指向了根节点,也就是说我们注定是先遍历中间节点,所以这样的方法并不适合中序迭代。

class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {stack<TreeNode*>s;vector<int>result;TreeNode*cur=root;while(cur!=nullptr||!s.empty()){if(cur){s.push(cur);cur=cur->left;}else{cur=s.top();s.pop();if(cur)result.push_back(cur->val);cur=cur->right;}}return result;}
};

标记迭代法

那么有没有可以将三种迭代统一起来的代码呢?也是有的,这里的思路也是创建一个栈来模拟,不同的是,我们将凡是已经遍历过的数据一股脑地放进去,在我们要处理的数据之后紧接着加入一个null来标记,这种思路也被称为标记迭代法。当我们遍历到null的时候,就对下一数据进行加入答案数组的处理。

中序

class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {vector<int> result;stack<TreeNode*> st;if (root != NULL) st.push(root);while (!st.empty()) {TreeNode* node = st.top();if (node != NULL) {st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中if (node->right) st.push(node->right);  // 添加右节点(空节点不入栈)st.push(node);                          // 添加中节点st.push(NULL); // 中节点访问过,但是还没有处理,加入空节点做为标记。if (node->left) st.push(node->left);    // 添加左节点(空节点不入栈)} else { // 只有遇到空节点的时候,才将下一个节点放进结果集st.pop();           // 将空节点弹出node = st.top();    // 重新取出栈中元素st.pop();result.push_back(node->val); // 加入到结果集}}return result;}
};

该思路旨在if条件语句中处理压栈操作,else里处理加入答案数组,使代码变得简介,但是思路难想到,建议只记一种思路。

总结:

今天我们完成了树的递归遍历和非递归遍历,了解了一种新的方法标记迭代法,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

http://www.dtcms.com/a/496624.html

相关文章:

  • 个人做网站怎么赚钱企业如何网络营销推广
  • 路由器屏蔽网站怎么做具有营销型网站的公司
  • 企业网站建设要素建设公司官网的请示
  • 苏州网站建设哪里好个人网站 费用
  • 位操作符a
  • GaussDB 应用侧报no pg_hba.conf entry for host处理方法
  • Linux中内存初始化mem_init函数的实现
  • 怎么做微信钓鱼网站吗有哪些设计好看的企业官网
  • html做的网页怎么变成网站seo分析网站
  • 沈阳网站建设技术公司怎么登陆自己的公司网站
  • nextjs前端工程如何打包部署(nginx)
  • 网站设计与建设的阿里巴巴代加工平台
  • 高性能物联网双轴倾角传感器及其可靠厂家选择指南
  • 一个网站如何做桌面快捷链接建设银行网站会员基本信息
  • 广州汽车网站建设国外做的比较好的购物网站
  • 深度学习2-损失函数-数值微分-随机梯度下降法(SGD)-反向传播算法
  • 濮阳网站建设熊掌号网站建设捌金手指花总五
  • 深度剖析:Feign 调用第三方接口 + Token 自动续期(24 小时有效期 + 1/4 时间触发)实战指南
  • AgentScope RAG 示例指南
  • 做网站学哪种代码好jquery 显示 wordpress
  • 做网站模板的网页名称是m开头swiper wordpress
  • 首京建设投资引导基金网站海淀重庆网站建设
  • NumPy random.choice() 函数详解
  • 网站手机端 怎么做东莞工业品网站建设
  • 广东网站建设网站前端一个页面多少钱
  • Redis分布式锁、Redisson及Redis红锁知识点总结
  • 企业网络建站动漫制作专业专升本大学
  • 东莞网站建设推广方案制作一个网站多少钱啊
  • Spark Shuffle 分区与 AQE 优化
  • 上海住建部网站wordpress下载按钮插件