剑指offer_面试题6_重建二叉树(分解步骤,逐个击破)
题目:输入某二叉树的前序遍历和中序遍历的结果。请重建出该二叉树。如果输入的前序遍历和中序遍历的结果中都不含反复的数字。
比如:输入前序遍历 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7,2,1,5,3,8,6},则重建出图2.6所看到的的二叉树并输出它的头结点。
感触:复杂问题,要将它分解成一个个小问题,逐个击破,从而解决大问题。
我们都知道一个概念。知道 前序遍历 和 中序遍历。能够唯一确定一颗二叉树。
因此,我们首先须要怎样依据这两个已知条件,来画出这颗二叉树。在解决这道题的时候,最好用纸和笔。自己先实现一遍,然后分析自己实现的过程。分解每个步骤,而问题的算法就是依据你解决这个问题的步骤而来。
我在做的过程中,曾參考书中代码,然而别人的代码终究不是自己的。是别人的思路,自己在理解的过程中,总有这样那样的问题。因此。最好将书上的代码放一边,自己动手
去实践。依照自己的思路来解决整个问题。这样你在測试的时候。才有针对性。当然对于书中代码呈现的解决思路,须要选择性吸收。
对于这个问题,我把它分成三步:
1、首先拿到前序遍历序列,其作用就是用来取得 根节点。
(须要理解,二叉树是一个递归的过程,其子树亦是一个二叉树。每一次都是取得 二叉树的根节点)
2、找到 “前序遍历中取得的根节点” 在中序遍历序列中的位置
3、找到该位置后,就能够确定 该根节点 所接的左右子树(例如以下图所看到的),然后对这 子 二叉树进行递归操作。
这样又从第一步開始了。依次取得每一棵子二叉树的根节点。从而完毕整棵树的重建。
代码例如以下:
在解决这个问题的过程中,常常出现考虑问题不全面的问题,比方 以下代码中,加的一个函数 Judge_array()。它用来測试当你输入的前序序列和中序序列 不匹配的情况。这一点一開始乜有考虑到。
须要 铭记。警醒!
剑指offer中。有句话说的非常好,“最好在写代码前,考虑好測试用例“。在撸代码的过程中,特别有感触。
/****************************************************************************/
/** 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 */
/** 如果输入的前序遍历和中序遍历的结果中都不含反复的数字。比如 */
/** 输入前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6} */
/** 则重建出图2.6所看到的的二叉树并输出它的头结点。 */
/** 时间:2015.7.25 作者:jwt */
/****************************************************************************/
#include <iostream> using namespace std; typedef struct node {
int value;
struct node *lchild;
struct node *rchild;
}BiTree_Node; /**用于推断前序遍历序列和中序遍历数列书否匹配*/
bool Judge_array(int *pre,int *in,int n)
{
int i, j;
int k = 0;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
if(pre[i] == in[j])
k++;
}
}
if(k != n)
return false;
else
return true;
} /*重建二叉树的递归操作,对于这个问题。用指针更加方便 */
BiTree_Node *Construct(int *pre_start, int *in_start, int len)
{
/**对于前序遍历数列,仅仅做一件事,取得根节点root */
int root_value = pre_start[0];
BiTree_Node *root;
root = new BiTree_Node;
root->value = root_value;
root->lchild = NULL;
root->rchild = NULL; /**在中序遍历中寻找上面取得的root的位置*/
int k = 0;
int new_len;
while(root_value != in_start[k] && k < len)
{
k++;
}
new_len = k; /**依据所找到的位置,推断左右子树*/
if(new_len > 0)
{
root->lchild = Construct(pre_start+1, in_start, new_len);
/*new_len 表示左子树的长度*/
}
if(len - new_len - 1> 0)
{
root->rchild = Construct(pre_start+new_len+1, in_start+new_len+1, len-new_len-1);
/*len-new_len-1 表示右子树的长度*/
} return root;
} /*重建二叉树函数*/
BiTree_Node *Construct_BiTree(int pre[],int in[],int length)
{
if(pre == NULL || in == NULL || length <= 0 || !Judge_array(pre, in, length))
return NULL;
else
return Construct(pre, in, length);
} /**二叉树后序遍历。通过后序遍历推断重建的二叉树是否正确*/
void Postorder(BiTree_Node *root)
{
if(NULL == root)
return;
else{
Postorder(root->lchild);
Postorder(root->rchild);
cout << root->value << ' ';
}
} int main()
{
int pre[8] = {1,2,4,7,3,5,6,8};
int in[8] = {4,7,2,1,5,3,8,6}; //int pre[5] = {1,2,3,4,5};
//int in[5] = {5,4,3,2,1}; //int pre[6] = {1,2,3,6,7,8};
//int in[6] = {3,2,1,6,7,8}; //int pre[5] = {1,2,3,4,5};
//int in[5] = {1,2,3,4,6}; BiTree_Node *root = Construct_BiTree(pre,in,8);
Postorder(root);
return 0;
}
结果例如以下:(能够用主函数凝视部分。測试其它情况)
/*点滴积累,我的一小步O(∩_∩)O~*/
剑指offer_面试题6_重建二叉树(分解步骤,逐个击破)的更多相关文章
- 剑指offer面试题6 重建二叉树(c)
- 剑指offer面试题6 重建二叉树(java)
注:(1)java中树的构建 (2)构建子树时可以直接利用Arrays.copyOfRange(preorder, from, to),这个方法是左开右闭的 package com.xsf.SordF ...
- 剑指Offer_编程题之重建二叉树
题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...
- 剑指Offer:面试题6——重建二叉树(java实现)
问题描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不包含重复的数字. 例如: 输入:前序{1,2,4,7,3,5,6,8},中序{4,7,2,1 ...
- C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解
剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...
- 剑指Offer - 九度1385 - 重建二叉树
剑指Offer - 九度1385 - 重建二叉树2013-11-23 23:53 题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的 ...
- 剑指offer【04】- 重建二叉树(java)
题目:重建二叉树 考点:树 题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6, ...
- 剑指offer(4)重建二叉树
题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...
- 剑指offer——面试题8:二叉树的下一个节点
// 面试题8:二叉树的下一个结点 // 题目:给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个结点? // 树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父结点的指针. ...
随机推荐
- The broken pedometer-纯暴力枚举
The broken pedometer Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu i ...
- Swift 字典的经常用法
/* * *要正确使用字典,也须要一些条件 * 1.字典键值对的键和值的类型必须明白,能够直接指定.也能够类似数组直接赋值由编译器自己主动识别 * 2,字典必需要初始化 * 3,键的类型必须是能够被哈 ...
- Vim 删除不包含指定字符串的行及统计匹配个数
Vim 删除不包含指定字符串的行及统计匹配个数 转载▼ Help :g/pattern/d 是找到pattern, 删之 :v/pattern/d 是找到非pattern, 删之 :%s/xx ...
- HBase框架基础(四)
* HBase框架基础(四) 上一节我们介绍了如何使用HBase搞一些MapReduce小程序,其主要作用呢是可以做一些数据清洗和分析或者导入数据的工作,这一节我们来介绍如何使用HBase与其他框架进 ...
- leetcode 新题型----SQL,shell,system design
leetcode 主要是一个针对北美的coder人群找工作的代码练习网站,我在2015年初次接触这个网站的时候,总共只有200多道题目,是一个类似acm 的a题网站.这些年变化越来越大,主要是因为找工 ...
- #p-complete原来比np更难
转载一下豆瓣的一个不知名的朋友的介绍: NP是指多项式时间内验证其解是否正确.比如: 我们给一个0-1背包的解,就可以在多项式时间内验证是否满足条件.至于是否能找到 满足条件的解,这在NP复杂度里没有 ...
- OpenGL编程逐步深入(十)索引绘制
准备知识 OpenGl提供了一些绘图函数.到目前为止我们使用的glDrawArrays绘图函数属于"顺序绘制".这意味着顶点缓冲区从指定的偏移量开始被扫描,每X(点为1,直线为2等 ...
- c# 对用户密码加密解密
一.使用16位.32位.64位MD5方法对用户名加密 1)16位的MD5加密 ? 1 2 3 4 5 6 7 8 9 10 11 12 /// <summary> /// 16位MD5加密 ...
- c# 的类成员
1 字段和变量的区别 字段是在类中定义的数据成员 由访问修饰符+数据类型+字段名(public string name) 字段就像类的一个小数据库,用来存放和类相关的数据; 而变量是没有修饰符的(in ...
- [USACO14FEB]路障Roadblock
题目:洛谷P2176. 题目大意:有n个点m条无向边,一个人要从1走到n,他会走最短路.现在可以让一条边的长度翻倍,求翻倍后这个人要多走多少距离. 解题思路:首先可以知道,翻倍肯定是在最短路上的某条边 ...