中序遍历+后序/先序遍历构建二叉树

@(算法学习)

给定中序+先序,中序+后序可以唯一构建一棵二叉树。

给定先序+后序,无法唯一确定,但是却是很好的考点,问总共有多少种可能。。。如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

中序遍历+后序/先序遍历构建二叉树相关推荐

  1. 【C++】二叉树的先序、中序、后序遍历序列

    二叉树常用到的遍历有这三种 先序遍历:先遍历根节点,然后再分别遍历左节点和右节点.(根左右) 中序遍历:先遍历左节点,然后再遍历根节点,最后遍历右节点.(左根右) 后序遍历:先遍历左节点,然后再遍历右 ...

  2. 二叉树的前序、中序、后序遍历非递归实现

    这是leetcode上的3个题目,要求用非递归实现,其中以后序遍历实现最难,既然递归实现的三种遍历程序只需要改变输入代码顺序,为什么循环不可以呢,带着这种执拗的想法,我开始了这次研究 我依然是将递归用 ...

  3. NC45实现二叉树先序、中序和后序遍历

    文章目录 解法1:Morris 算法 题目地址   如标题,实现二叉树的三序遍历. 例   输入:1, 2, 3   输出:[[1, 2, 3], [2, 1, 3], [2, 3, 1]]   输出 ...

  4. 二叉树深度优先 java_二叉树遍历(前序、中序、后序、层次、深度优先、广度优先遍历) java实现...

    二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的.对于二叉树,有深度遍历和广度遍历,深度遍历有前序.中序以及后序三种遍历方法,广度遍历即我们寻常所说的层次遍历.由于树的 ...

  5. 4.二叉树的先序、中序以及后序遍历的递归写法与非递归写法(LeetCode第94、144、145题)

    一.递归法 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是"一看就会,一写就废". 主要是对递归不成体系,没有方法论,每次写递归算法 ,都是靠玄学来写代码,代码能不能编过都 ...

  6. 二十五、二叉树的前序、中序、后序遍历

    一.为何使用树这种数据结构 数组存储方式的分析 优点:通过下标方式访问元素,速度快.对于有序数组,还可使用二分查找提高检索速度. 缺点:如果要检索具体某个值,或者插入值(按一定顺序)会整体移动,效率较 ...

  7. 手动创建一棵二叉树,然后利用前序、中序、后序、层序进行遍历(从创建二叉树到各种方式遍历)(含运行结果)

    手动创建一棵二叉树,然后利用前序.中序.后序.层序进行遍历 import java.util.LinkedList; import java.util.List; import java.util.Q ...

  8. 把一个数组的值存入二叉树中,然后利用前序、中序、后序3种方式进行遍历(完整代码以及运行结果)(Java)

    把一个数组的值存入二叉树中,然后利用前序.中序.后序3种方式进行遍历(完整代码以及运行结果) 在最近的面试过程中,听说有小伙伴被面试官要求创建二叉树,然后对该二叉树进行遍历,感觉这一直以来都是一个大家 ...

  9. 【LeetCode系列】从中序与后序遍历序列构造二叉树 从前序与中序遍历序列构造二叉树...

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 105. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树 ...

  10. php循环方法实现先序、中序、后序遍历二叉树

    二叉树是每个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(right subtree). <?phpnam ...

最新文章

  1. HTML上传excel文件,php解析逐条打印输出
  2. 站点安全预警,建议大家多重禁止load_file函数!
  3. 洛谷 - P1758 [NOI2009]管道取珠(计数dp)
  4. bim 模型web页面展示_BIM+装配式建筑工程师2020年必须拿下的技能证书
  5. 7135制作自动量程电压切换_基于数字电压表的直流电位差计自动检定装置的讨论...
  6. android navigation bar高度,Android获取屏幕真实高度包含NavigationBar(底部虚拟按键)
  7. Oracle备份standby,Oracle 11g 利用泠备份恢复standby库
  8. 求和函数sumx_PowerBI公式-SUMX 函数
  9. hdu 3062 Party(2-sat,3级)
  10. Tableau的简单数据可视化操作
  11. 自学python免费教材-Python 有哪些入门学习方法和值得推荐的经典教材?
  12. 三个 CSS 预处理器(框架):Sass、LESS 和 Stylus
  13. java静态类堆栈_Java回归学习-面向对象内存分析-堆栈
  14. 2021-06-19表单,内嵌框架
  15. 【GitHub Desktop】(GitHub Windows桌面版) 中文汉化,(GitHub客户端汉化,非网页端插件)
  16. 区块链升为国家战略,它就升天了么?
  17. 计算机网络路由交换技术运用,计算机网络路由交换的技术应用与发展趋势研究...
  18. js实现手机摇一摇功能
  19. Juniper路由器基本命令及中文解
  20. 中科院计算所陈云霁:深度学习芯片剩下的只是工程问题,我们要起航探索新方向

热门文章

  1. c++中的构造函数和析构函数
  2. 仿射解密c语言程序实验报告,仿射加密解密 - 依姆哣特的个人空间 - OSCHINA - 中文开源技术交流社区...
  3. ccf矩阵java_CCF系列之矩阵(201512-5)
  4. mac 您没有权限打开应用程序_Mac应用程序无法打开或文件损坏的解决方法
  5. redis 判断存在性_一口气说出四种幂等性解决方案,面试官露出了姨母笑~
  6. c语言三种循环语句,C语言三种循环语句的功能等价性
  7. mysql临时表如何分页查询慢_面试官扎心一问:数据量很大,分页查询很慢,有什么优化方案?...
  8. cenyos7安装 yum不可用_centos7安装fabric
  9. python爬取js script中的变量_BeautifulSoup抓取js变量
  10. android自定义渐变色圆环,CircleShape渐变颜色圆环