IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【算法】【树】已知先序中序序列求后序序列(详细解释) -> 正文阅读

[数据结构与算法]【算法】【树】已知先序中序序列求后序序列(详细解释)

题目描述

如题所示,已知先序中序序列建树与求后序序列

算法原理

????????利用递归和分制的思想,找到当前树先序序列的根节点,然后找到对应中序序列的位置,然后根据根节点在中序序列中的位置来判断左右子树分别的位置,然后继续对左右子树进行递归,最后得出结果

post(0, 0, 序列总长度-1);
void post(int root, int start, int end)

?????????首先是递归函数进入,其中三个形参分别代表的含义为

? ? ? ????????? root? ? ? ? 先序序列中当前递归层中根节点的下标

? ? ? ????????? start? ? ? ? 中序序列中子树的最左下标(子树开始的下标)

? ? ? ????????? end? ? ? ? 中序序列中子树的最右下标(子树结束的下标)

if(start > end)     return ;

?????????递归结束的标志,因为子树的元素范围在下标[start,end]之内,当start>end的时候,说明以当前节点为空节点

int i = start;

? ? ? ? 这里的i相当于只在中序遍历中有效,这里的i对于查找根节点root的先序序列完全没有意义,仅代表root在中序序列中的下标位置

例子:

?假设一棵二叉树为上面的形式,那么他的先序序列和中序序列为

先序序列1234567891011
中序序列4352768110911

递归原理:

? ? ? ? 重点要解释一下这里的两条递归语句,分别代表递归当前根节点的左子树和当前根节点的右子树

????????对于左子树

post(root + 1, start, i - 1);    //递归左子树
根节点左子树右子树
先序序列1234567891011
rootroot+1
根节点左子树的根节点
左子树根节点右子树
中序序列4352768110911
i-1i
startend

???????如图可见,当遍历左子树的时候,

???????对于先序序列,左子树的根节点为先序序列上一层根节点root的下一个节点,也就是root+1

???????对于中序序列,因为是左子树,所以启始start值不变,end应该为在中序序列中找到的根节点i的前一个节点也就是i-1

????????对于右子树

post(root + 1 + i - start, i + 1, end);
根节点左子树右子树
先序序列1234567891011
rootroot+1root+(i-start)root+(i-start)+1
根节点左子树的根节点
左子树的元素个数=i-start
左子树根节点右子树
中序序列4352768110911
i-1ii+1
startend

中序序列中的启始位置和结束位置都比较好确定,启始位置为i+1,结束位置为end

????????主要的难点就在于root的确认,我们能知道在先序序列中,是按照根节点——左子树——右子树排列的,左子树的根节点在先序序列中就为本层的根节点+1(root+1),比较好确定,但是右子树的跟节点就没有那么好确认了,但是我们细想就可以知道,原本的根节点加上左子树的节点个数,那不就到了右子树了嘛,但是这个想法也不准确

????????首先左子树的节点个数可以根据中序序列来判断,为i-start,但是根节点加上左子树的节点总数(root+(i-start))仅仅代表了左子树的最右侧节点,再加1才能代表右子树的第一个端点

? ? ? ? 有这幅图就可以比较清楚的看出

? ? ? ? 那么就引出了另一个问题了为什么根节点不能直接是i+1,而是要绕这么大一个圈子回来呢?

? ? ? ? 这就需要下一步递归来判断了?

父节点的左子树
父节点新的根节点左子树右子树父节点的右子树子树
先序序列1234567891011
root
父节点的左子树
左子树新的根节点右子树父节点父节点的右子树
中序序列4352768110911
i-1ii+1
startend

?这样就比较容易能看出来了,正确的根节点应该是6

但是i+1仅仅表示7,明显与答案不符

实际上i仅仅在中序序列中有意义,放在先序序列中并没有什么意义

核心代码实现

参考柳婼已知前序(先序)与中序输出后序_柳婼 の blog-CSDN博客

#include <cstdio>
using namespace std;
int pre[] = {1,2,3,4,5,6,7,8};
int in[] = {4,3,5,2,7,6,8,1};
void post(int root, int start, int end) {
    //root? ? ? ? 先序序列中当前递归层中根节点的下标
    //start? ? ? ? 中序序列中子树的最左下标(子树开始的下标)
    //end? ? ? ? 中序序列中子树的最右下标(子树结束的下标)
    if(start > end)     return ;    /*递归结束的标志,因为子树的元素范围在下标[start,end]之内,当start>end的时候,说明以当前节点为空节点*/
    int i = start;    //这里的i对于查找根节点root的先序序列完全没有意义,仅代表root在中序序列中的下标位置
    while(i < end && in[i] != pre[root]) i++;    //寻找root在中序序列中的位置
    post(root + 1, start, i - 1);                //递归左子树
    post(root + 1 + i - start, i + 1, end);        //递归右子树
    printf("%d ", pre[root]);                    //输出后序序列
}
 
int main() {
    post(0, 0, 7);
    //这里的总长度是pre.size()-1,而不是pre.size()
    return 0;
}

例题

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-15 18:33:00  更:2021-12-15 18:33:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:55:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码