求二叉树序遍历

前言 :这是一道很简单的题目对吧,但本蒟蒻还是想写写去帮助那些不会的人。

介绍一下树的几种遍历
先序遍历
先序遍历(Pre-order),先序就是按照最优先顺序,遍历就是沿一定路径经过路径上所有的站。在二叉树中,先根后左再右。巧记:根左右。

typedef struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
    struct TreeNode *parent;
} TreeNode;
void middle_order(TreeNode *Node) {
    if(Node != NULL) {
        printf("%d ", Node->data);
        middle_order(Node->left);
        middle_order(Node->right);
    }
}

中序遍历
中序遍历(In-order)是二叉树遍历的一种,也叫做中根遍历、中序周游。在二叉树中,先左后根再右。巧记:左根右。

typedef struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
    struct TreeNode *parent;
} TreeNode;
void middle_order(TreeNode *Node) {
    if(Node != NULL) {
        middle_order(Node->left);
        printf("%d ", Node->data);
        middle_order(Node->right);
    }
}

后序遍历
后序遍历(Post-order)是二叉树遍历的一种,也叫做后根遍历、后序周游,可记做左右根。后序遍历有递归算法和非递归算法两种。在二叉树中,先左后右再根。巧记:左右根。

typedef struct TreeNode {
    int data;
    struct TreeNode *left;
    struct TreeNode *right;
    struct TreeNode *parent;
} TreeNode;
void middle_order(TreeNode *Node) {
    if(Node != NULL) {
        middle_order(Node->left);
        middle_order(Node->right);
        printf("%d ", Node->data);
    }
}

实际上说白了就是printf的位置的变化:
最前(先序遍历)->中间(中序遍历)->最后(后序遍历)

首先我们要知道我们可以
①知道 中序+先序->后序
②知道 中序+后序->先序

为什么不可以 知道 后序中序求先序呢?
考虑如下图中的几棵二叉树:

这里写图片描述

所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。

但是知道中序和(后序/先序)就能求(先序/后序)(这里就不做证明了,想想就知道了)


假设有棵树,长下面这个样子,它的前序遍历,中序遍历,后续遍历都很容易知道。
这里写图片描述
PreOrder: GDAFEMHZ
InOrder: ADEFGHMZ
PostOrder: AEFDHZMG


一、已知前序(pre_order)、中序(in_order)遍历,求后序(post_order)遍历
PreOrder: GDAFEMHZ
InOrder: ADEFGHMZ

第一步,根据前序遍历的特点,我们知道根结点为第一位——G

第二步,观察中序遍历ADEFGHMZ。其中根节点G左侧的ADEF必然是他的的左子树根节点G右侧的HMZ必然是他的的右子树

第三步,观察左子树ADEF,左子树的中的根节点必然是他(左子树的中的根节点)父亲的左儿子。在前序遍历中,他父亲的左儿子位于他父亲的后一位,所以左子树的根节点为D。

第四步,同样的道理,根节点的右子树HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把根和根的所有左子树节点遍历完之后才会遍历右子树并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点

第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。该步递归的过程可以简洁表达如下:

1 确定根,确定左子树,确定右子树。

2 在左子树中递归。

3 在右子树中递归。

4 打印当前根。

那么,我们就能求出这棵树的后序遍历了

#include<cstdio>
#include<cstring>
void post_order(char*in_order,char*pre_order,int length){
    if(!length)return;
    int root_index=0;
    for(;root_index<length;root_index++)
        if(in_order[root_index]==*(pre_order))break;
    post_order(in_order,pre_order+1,root_index);
    post_order(in_order+root_index+1,pre_order+root_index+1,length-root_index-1);
    putchar(*(pre_order));
}
int main(){
    char*in_order=new char[1000];
    char*pre_order=new char[1000];
    gets(pre_order);gets(in_order);
    post_order(in_order,pre_order,strlen(in_order));
return 0;
}

(ps: root_index->根指针)
看代码是不是有点迷?如果是我们来一步一步图解一下
这里写图片描述
然后我们在中序遍历中找到根节点
这里写图片描述
因为中序遍历中根节点的左边就是他的左子树,右边就是他的右子树
然后左右子树的大小又是一定的,所以
这里写图片描述
于是我们确定了之后就可以继续向下递归了
然后我们又发现
这里写图片描述
这下我们就知道左右子树的大小(即长度)了

if(!length)return;

长度=0时,说明这个子树已经空了,所以要返回
然后递归下传的指针要怎么变呢?
我们只需要下传起始指针就ok了,因为我们已经知道长度了
我们数格子可以发现
这里写图片描述
于是我们就知道如何下传指针了

    post_order(in_order,pre_order+1,root_index);
    post_order(in_order+root_index+1,pre_order+root_index+1,length-root_index-1);

先遍历左子树,再遍历右子树
最后输出根节点

putchar(*(pre_order));

(觉得指针不好写的,可以改成下标变量也是可以的)

#include<cstdio>
#include<cstring>
char in_order[1000];
char pre_order[1000];
void post_order(int in,int pre,int length){
    if(!length)return;
    int root_index=0;
    for(;root_index<length;root_index++)
        if(in_order[in+root_index]==pre_order[pre])break;
    post_order(in,pre+1,root_index);
    post_order(in+root_index+1,pre+root_index+1,length-root_index-1);
    putchar(pre_order[pre]);
}
int main(){
    gets(pre_order);gets(in_order);
    post_order(0,0,strlen(in_order));
return 0;
}

一、已知后序(post_order)、中序(in_order)遍历,求前序(pre_order)遍历
PostOrder: AEFDHZMG
InOrder: ADEFGHMZ

第一步,根据后序遍历的特点,我们知道根结点为最后一位——G

第二步,观察中序遍历ADEFGHMZ。其中根节点G左侧的ADEF必然是他的的左子树根节点G右侧的HMZ必然是他的的右子树

第三步,观察左子树ADEF,左子树的中的根节点必然是他(左子树的中的根节点)父亲的左儿子。在后序遍历中,他父亲的左子树位于最前面几(左子树的大小)位,即AEFD,根据后序遍历的性质,这棵子树的根节点是这个子树后序遍历的最后一位,所以左子树的根节点为D。

第四步,同样的道理,根节点的右子树HMZ中的根节点也可以通过后序遍历求得。在后序遍历中,一定是先把根的所有左子树节点遍历完之后才会遍历右子树并且遍历的左子树的最后一个节点就是左子树的根节点。同理,遍历的右子树的最后一个节点就是右子树的根节点

第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。该步递归的过程可以简洁表达如下:

1 确定根,确定左子树,确定右子树。

2 打印当前根

3 在左子树中递归。

4 在右子树中递归。

那么,我们就能求出这棵树的前序遍历了

#include<cstdio>
#include<cstring>
void pre_order(char*in_order,char*post_order,int length){
    if(!length)return;
    int root_index=0;
    for(;root_index<length;root_index++)
        if(in_order[root_index]==*(post_order+length-1))break;
    putchar(*(post_order+length-1));
    pre_order(in_order,post_order,root_index);
    pre_order(in_order+root_index+1,post_order+root_index,length-root_index-1);
}
int main(){
    char*in_order=new char[1000];
    char*post_order=new char[1000];
    gets(in_order);gets(post_order);
    pre_order(in_order,post_order,strlen(in_order));
return 0;
}

图解过程和之前的差不多,这里就不再赘述了(其实理解上一个的,这一个也就没问题了)。

打开链接下载源码: https://pan.quark.cn/s/e23b4cd62d42 Linux运维工程师在IT行业扮演着核心的角色,他们承担着对基于Linux操作系统的服务器进行维护和管理的职责,以保障系统的稳定性和运行效率。Linux运维职业的学习和发展路径是结构化且周密的,它包含了从入门到精通的多个层次。以下是对这一主题的深入解析: 一、入门知识阶段 在Linux运维的学习初期,首要任务是掌握Linux操作系统的基本理念和常用指令。这涉及到对Linux不同发行版(例如Ubuntu、CentOS、Red Hat等)的认识,熟悉文件系统的构造,熟练运用文件和目录操作(诸如ls、cd、mkdir、rm等),以及掌握vi/vim等文本编辑器的使用方法。除此之外,学习Linux中的用户和权限管理、进程管理、网络设置和监控也是这一阶段需要重点关注的内容。 二、高级技术阶段 在基础知识的积累之后,需要进一步深入理解Linux内核、Shell脚本编程、系统服务和守护进程的管理。这一阶段应该熟练运用grep、awk、sed等数据处理工具,以及crontab定时任务的设定。同时,要学会通过系统日志进行故障排查,比如查看/var/log目录下的各种日志文件。对于网络服务的配置与管理,如HTTP(Apache或Nginx)、FTP、DNS、DHCP等,也具有非常重要的意义。 三、自动化与编程脚本 在当代运维工作中,自动化是提升工作效率的关键要素。学习Python或Perl等编程语言,编写自动化脚本来处理日常任务,例如系统备份、监控告警、数据整理等。了解Ansible、Puppet、Chef等配置管理工具,能够帮助实现更大范围的系统部署和管理。 四、性能调优与监控 掌握系统性能参...
内容概要:本文围绕虚拟电厂与电动汽车之间的主从博弈关系,结合条件风险价值(CVaR)理论,构建了一个考虑不确定环境下的优化决策模型。研究通过建立上层虚拟电厂调度优化与下层电动汽车用户充放电响应的双层博弈框架,利用CVaR量化参与主体的风险偏好,提升系统在电价波动、负荷不确定性等风险因素下的鲁棒性与经济性。采用Matlab进行仿真建模与解,验证了该方法在降低运行风险、提高收益水平及促进可再生能源消纳方面的有效性。文档还提供了丰富的相关研究主题和技术资源,涵盖电力系统优化、智能算法、深度学习、路径规划等多个前沿领域,展现了广泛的技术支持与科研应用潜力。; 适合人群:具备电力系统基础知识、优化理论背景及Matlab编程能力的科研人员,特别适用于从事能源互联网、电动汽车调度、虚拟电厂运营、风险管理与低碳电力系统研究的研究生与高校研究人员。; 使用场景及目标:① 掌握主从博弈在综合能源系统中的建模方法;② 学习CVaR在电力市场风险决策中的集成应用;③ 实践基于Matlab的双层优化模型实现与仿真分析;④ 借助配套资源拓展科研视野,支撑高水平论文撰写与课题申报。; 阅读建议:建议读者结合文中提供的百度网盘资料与公众号资源,获取完整代码、参考文献及复现案例,按照文档目录体系循渐进地学习,并动手调试仿真程,深入理解博弈结构设计与风险规避机制的实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值