中序遍历+后序/先序遍历构建二叉树
中序遍历+后序/先序遍历构建二叉树
@(算法学习)
给定中序+先序,中序+后序可以唯一构建一棵二叉树。
给定先序+后序,无法唯一确定,但是却是很好的考点,问总共有多少种可能。。。如2016.9月份PAT最后一题就是考察这个知识点。
#include <stdio.h>
#include <stdlib.h>struct node
{int data;struct node *left;struct node *right;
};struct node* newNode(int data)
{ struct node* nd = (struct node*)malloc(sizeof(struct node)); //分配空间 nd->data = data; //设置data域 nd->left = nd->right = NULL; //初始化左右孩子结点为NULL return nd;
} int mapIndex[256];
void mapToIndices(int inorder[], int n)
{int i;for (i=0; i<n; i++) {mapIndex[inorder[i]] = i;}
}
//在这之前要调用mapToIndices方法。pre数组为先序遍历序列,注意在递归过程中pre起始位置是变化的。n为结点数目,offset为子树开始位置。
struct node* buildInorderPreorder(int pre[],int n, int offset)
{if (n == 0) return NULL;int rootVal = pre[0];//根结点的值int i = mapIndex[rootVal] - offset;//从offset(含)开始到mapIndex[rootVal](不含)共i个结点是左子树struct node* root = newNode(rootVal);//新建结点//递归处理左右子树//左子树从第二个结点开始,第一个是根root->left = buildInorderPreorder(pre + 1,i, offset);//右子树从pre+i+1开始,pre+1是左子树根结点,pre+i是左子树最后一个结点,offset+i+1是右子树开始位置,与pre+i+1实际一致root->right = buildInorderPreorder(pre + i + 1,n - i - 1, offset + i + 1);return root;
}// 根据中序+后序
struct node *buildInorderPostorder(int post[], int n, int offset)
{ if (n == 0) return NULL; int rootVal = post[n-1];// 根 int i = mapIndex[rootVal]-offset; //i是左子树的结点个数 struct node *root = newNode(rootVal); // 新建结点 root->left = buildInorderPostorder(post, i, offset); //n-i-1是减掉左子树个数 - 根root->right = buildInorderPostorder(post + i, n - i -1, offset + i + 1); return root;
}void PreOrderTraverse(struct node *root)
{if(root == NULL){return;}printf("%d ",root->data);if(root->left != NULL){PreOrderTraverse(root->left);}if(root->right != NULL){PreOrderTraverse(root->right);}
}void InOrderTraverse(struct node *root)
{if(root == NULL){return;}if(root->left!=NULL){InOrderTraverse(root->left);}printf("%d ",root->data);if(root->right!=NULL){InOrderTraverse(root->right);}
}void PostOrderTraverse(struct node *root)
{if(root == NULL){return;}if(root->left != NULL){PostOrderTraverse(root->left);}if(root->right != NULL){PostOrderTraverse(root->right);}printf("%d ",root->data);}//测试代码
void buildInorderPreorderTest()
{int pre[] = {7, 10, 4, 3, 1, 2, 8, 11};int in[] = {4, 10, 3, 1, 7, 11, 8, 2};int n = sizeof(in) / sizeof(in[0]);int offset = 0;mapToIndices(in, n);struct node* root = buildInorderPreorder(pre, n, offset);printf("先序:");PreOrderTraverse(root);putchar('\n');printf("中序:"); InOrderTraverse(root);putchar('\n');printf("后序:");PostOrderTraverse(root);putchar('\n');
}
int main()
{buildInorderPreorderTest();return 0;
}
主要想强调几个基本点。
第一:从先序序列很容易找到第一个根,即为整棵树的根,而这个根需要确定它在中序序列中的位置。我们可以对中序序列进行查找,则耗时可能较长。谓为此特别设计了用哈希表存储的思路,存储的是中序序列元素的序号。
第二:此外,一个有趣的基本知识是,在数组中,两个元素下标之差,是左边元素(含此元素)到右边元素(不含)个数。这个小知识点在这部分非常重要。
而数组的第一个下标+数组长度,指向的是数组最后一个元素右边的位置,当然可以认为是溢出。
比如,i = mapIndex[rootVal]-offset;
根据根值在中序中锁定了位置,offset指的是左子树的起始位置,因此两个一减,得到的数值是从offset开始到根左边的元素的个数,即恰好为左子树的元素个数。
递归时,pre+1指向的是左子树的根,那么因为左子树有i个元素,则pre+1+i表示的是左子树第一个元素加上左子树的结点个数,指向的是右子树的第一个结点。
第三:递归时,用root->left去接左子树,用root->right 去接右子树。每次返回的是root,即当前层次新建的根结点。这个在二叉树构建中强调过。
事实上,递归可以很容易写,不必在脑海中跟着递归到很深的层次,而是应该抽出三个步骤:
- 先序序列的第一个元素是根结点值,构造这个结点,这是递归出口
- 根据中序序列划分左右子树,计算出左右子树的开始,长度,以及在先序序列中的开始
- 递归左右子树,按照函数的参数含义分别对应填好
第一层返回的是总的树根,那么注意往下层传递时,上一层分别伸出左右手接回来,这样层层递出去,还能通过这样的句柄归来,最终return root。
脑海中想回旋镖的运行过程,就是递归的两个阶段。
参考:
http://blog.csdn.net/sgbfblog/article/details/7783935
http://blog.csdn.net/sgbfblog/article/details/7764258
中序遍历+后序/先序遍历构建二叉树相关推荐
- 【C++】二叉树的先序、中序、后序遍历序列
二叉树常用到的遍历有这三种 先序遍历:先遍历根节点,然后再分别遍历左节点和右节点.(根左右) 中序遍历:先遍历左节点,然后再遍历根节点,最后遍历右节点.(左根右) 后序遍历:先遍历左节点,然后再遍历右 ...
- 二叉树的前序、中序、后序遍历非递归实现
这是leetcode上的3个题目,要求用非递归实现,其中以后序遍历实现最难,既然递归实现的三种遍历程序只需要改变输入代码顺序,为什么循环不可以呢,带着这种执拗的想法,我开始了这次研究 我依然是将递归用 ...
- NC45实现二叉树先序、中序和后序遍历
文章目录 解法1:Morris 算法 题目地址 如标题,实现二叉树的三序遍历. 例 输入:1, 2, 3 输出:[[1, 2, 3], [2, 1, 3], [2, 3, 1]] 输出 ...
- 二叉树深度优先 java_二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历) java实现...
二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的.对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历.由于树的 ...
- 4.二叉树的先序、中序以及后序遍历的递归写法与非递归写法(LeetCode第94、144、145题)
一.递归法 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是"一看就会,一写就废". 主要是对递归不成体系,没有方法论,每次写递归算法 ,都是靠玄学来写代码,代码能不能编过都 ...
- 二十五、二叉树的前序、中序、后序遍历
一.为何使用树这种数据结构 数组存储方式的分析 优点:通过下标方式访问元素,速度快.对于有序数组,还可使用二分查找提高检索速度. 缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动,效率较 ...
- 手动创建一棵二叉树,然后利用前序、中序、后序、层序进行遍历(从创建二叉树到各种方式遍历)(含运行结果)
手动创建一棵二叉树,然后利用前序.中序.后序.层序进行遍历 import java.util.LinkedList; import java.util.List; import java.util.Q ...
- 把一个数组的值存入二叉树中,然后利用前序、中序、后序3种方式进行遍历(完整代码以及运行结果)(Java)
把一个数组的值存入二叉树中,然后利用前序.中序.后序3种方式进行遍历(完整代码以及运行结果) 在最近的面试过程中,听说有小伙伴被面试官要求创建二叉树,然后对该二叉树进行遍历,感觉这一直以来都是一个大家 ...
- 【LeetCode系列】从中序与后序遍历序列构造二叉树 从前序与中序遍历序列构造二叉树...
关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 105. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树 ...
- php循环方法实现先序、中序、后序遍历二叉树
二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree). <?phpnam ...
最新文章
- HTML上传excel文件,php解析逐条打印输出
- 站点安全预警,建议大家多重禁止load_file函数!
- 洛谷 - P1758 [NOI2009]管道取珠(计数dp)
- bim 模型web页面展示_BIM+装配式建筑工程师2020年必须拿下的技能证书
- 7135制作自动量程电压切换_基于数字电压表的直流电位差计自动检定装置的讨论...
- android navigation bar高度,Android获取屏幕真实高度包含NavigationBar(底部虚拟按键)
- Oracle备份standby,Oracle 11g 利用泠备份恢复standby库
- 求和函数sumx_PowerBI公式-SUMX 函数
- hdu 3062 Party(2-sat,3级)
- Tableau的简单数据可视化操作
- 自学python免费教材-Python 有哪些入门学习方法和值得推荐的经典教材?
- 三个 CSS 预处理器(框架):Sass、LESS 和 Stylus
- java静态类堆栈_Java回归学习-面向对象内存分析-堆栈
- 2021-06-19表单,内嵌框架
- 【GitHub Desktop】(GitHub Windows桌面版) 中文汉化,(GitHub客户端汉化,非网页端插件)
- 区块链升为国家战略,它就升天了么?
- 计算机网络路由交换技术运用,计算机网络路由交换的技术应用与发展趋势研究...
- js实现手机摇一摇功能
- Juniper路由器基本命令及中文解
- 中科院计算所陈云霁:深度学习芯片剩下的只是工程问题,我们要起航探索新方向
热门文章
- c++中的构造函数和析构函数
- 仿射解密c语言程序实验报告,仿射加密解密 - 依姆哣特的个人空间 - OSCHINA - 中文开源技术交流社区...
- ccf矩阵java_CCF系列之矩阵(201512-5)
- mac 您没有权限打开应用程序_Mac应用程序无法打开或文件损坏的解决方法
- redis 判断存在性_一口气说出四种幂等性解决方案,面试官露出了姨母笑~
- c语言三种循环语句,C语言三种循环语句的功能等价性
- mysql临时表如何分页查询慢_面试官扎心一问:数据量很大,分页查询很慢,有什么优化方案?...
- cenyos7安装 yum不可用_centos7安装fabric
- python爬取js script中的变量_BeautifulSoup抓取js变量
- android自定义渐变色圆环,CircleShape渐变颜色圆环