面试题五 重建二叉树
2014-03-18 16:16
239 查看
题目
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
分析
1. 取先序遍历的第一个值为树的根结点
2. 在中序遍历中找到1中的那个结点
3. 中序遍历中,处于该结点左侧的所有结点,是该树左子树的中序遍历;处于该结点右侧的所有结点,是该树右子树的中序遍历。
4. 前序遍历中,左右子树的前序遍历也是分开放的。因此根据3中获得的中序遍历的长度,可以将前序遍历分割为左右子树的前序遍历。
根据这个思路,就可以写出递归算法/程序了。
代码实现( 含测试 )
[b]运行测试
正常输入:
异常输入( 结点数为0或负数 ):
异常输入( 前序,中序序列不匹配 ):
小结
1. 对于一些较为复杂的问题,需要通过画图来细致分析,从而发现规律。
2. 分析问题要全面,应当在考虑到一般输入后,思考特殊输入的问题。
3. 递归思想可以解决很多经典的问题。
4. 留意函数参数的传递方式是值传递,尤其是在传递的参数为指针时。必要时采用引用可以避免繁琐的多级指针。
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
分析
1. 取先序遍历的第一个值为树的根结点
2. 在中序遍历中找到1中的那个结点
3. 中序遍历中,处于该结点左侧的所有结点,是该树左子树的中序遍历;处于该结点右侧的所有结点,是该树右子树的中序遍历。
4. 前序遍历中,左右子树的前序遍历也是分开放的。因此根据3中获得的中序遍历的长度,可以将前序遍历分割为左右子树的前序遍历。
根据这个思路,就可以写出递归算法/程序了。
代码实现( 含测试 )
#include <iostream> using namespace std; // 定义二叉树结点类型 struct BinaryTreeNode { int value; BinaryTreeNode * left; BinaryTreeNode * right; }; // 构建二叉树函数 BinaryTreeNode * construct( BinaryTreeNode * &T, int *pre, int *in, int len ); // 遍历函数 void preOrderPrint( BinaryTreeNode *T ); void inOrderPrint( BinaryTreeNode *T ); void postOrderPrint( BinaryTreeNode *T ); // 定义最大处理结点数 const int MAX = 1000; // 定义合法标志 int TAG=0; int main() { int preOrder[MAX]; int inOrder[MAX]; /* * 获取前序和中序序列。 */ int n; cout << "请输入树的结点数( 前/中序遍历的长度 ):" << endl; cin >> n; if (n >= MAX) { cout << "结点数过大!" << endl; return 1; } if (n <= 0) { cout << "输入结点数异常,无法构造树。" << endl; return 1; } cout << "请输入前序遍历序列:" << endl; for (int i=0; i<n; i++) { cin >> preOrder[i]; } cout << "请输入中序遍历序列:" << endl; for (int i=0; i<n; i++) { cin >> inOrder[i]; } // 初始化根结点,前序遍历起点,中序遍历起点。 BinaryTreeNode * T=NULL; int *pre = preOrder; int *in = inOrder; // 调用构建函数构建二叉树 T = construct( T, preOrder, inOrder, n ); // 如果输入的前序和中序序列不匹配。 if (TAG == 1) { cout << "前序和中序序列不匹配,构造失败。" << endl; return 1; } // 构建成功,打印此二叉树。 cout << endl << "构建成功,下面输出此二叉树:" << endl; cout << "前序:" << endl; preOrderPrint(T); cout << endl; cout << "中序:" << endl; inOrderPrint(T); cout << endl; cout << "后序:" << endl; postOrderPrint(T); cout << endl; return 0; } // 第一个参数务必要声明为指针的引用类型 BinaryTreeNode * construct( BinaryTreeNode * &T, int *pre, int *in, int len ) { // 如果输入的前序和中序序列不匹配 if (TAG == 1) return NULL; // 如果为空树 if (len == 0) { return NULL; } // 构造新结点 T = new BinaryTreeNode(); T->value = pre[0]; // 找到中序遍历数组中左右子树的" 分割点 " int i=0; while (in[i] != pre[0]) { i++; } // 如果输入的前序和中序序列不匹配 if (i >= len) { TAG = 1; return NULL; } // a, b为左,右子树的前序遍历在pre的起始位置 int a,b; // p, q为左,右子树的中序遍历在in中的起始位置 int p,q; p = 0; q = i+1; a = 1; b = q; // 递归构建左子树 T->left = construct(T->left, &pre[a], &in[p], i); // 递归构建右子树 T->right = construct(T->right, &pre, &in[q], len-i-1); return T; } /* * 三种测试用的遍历函数 */ // 先序 void preOrderPrint( BinaryTreeNode *T ) { if (!T) return; cout << T->value << " "; preOrderPrint(T->left); preOrderPrint(T->right); } // 中序 void inOrderPrint( BinaryTreeNode *T ) { if (!T) return; inOrderPrint(T->left); cout << T->value << " "; inOrderPrint(T->right); } // 后序 void postOrderPrint( BinaryTreeNode *T ) { if (!T) return; postOrderPrint(T->left); postOrderPrint(T->right); cout << T->value << " "; }
[b]运行测试
正常输入:
异常输入( 结点数为0或负数 ):
异常输入( 前序,中序序列不匹配 ):
小结
1. 对于一些较为复杂的问题,需要通过画图来细致分析,从而发现规律。
2. 分析问题要全面,应当在考虑到一般输入后,思考特殊输入的问题。
3. 递归思想可以解决很多经典的问题。
4. 留意函数参数的传递方式是值传递,尤其是在传递的参数为指针时。必要时采用引用可以避免繁琐的多级指针。
相关文章推荐
- 剑指offer面试题6 重建二叉树(java)
- 剑指Offer之面试题6:重建二叉树
- 面试题 6: 重建二叉树
- 【面试题】剑指offer06--重建二叉树
- 《剑指Offer》面试题6:重建二叉树
- 剑指offer--面试题6:重建二叉树--Java实现
- 剑指offer-面试题6:重建二叉树
- 《剑指Offer》学习笔记--面试题6:重建二叉树
- 剑指Offer面试题6(Java版):重建二叉树
- 【剑指offer】面试题六:重建二叉树
- 剑指offer面试题6:重建二叉树
- 剑指offer 面试题6 重建二叉树
- 剑指Offer面试题6重建二叉树(根据前序中序输出后序)
- 剑指offer面试题七之重建二叉树
- 剑指Offer面试题6(Java版):重建二叉树
- 面试题03 - 重建二叉树 【树】[ 一定要记住 ]
- 面试题6:重建二叉树
- P55、面试题6:重建二叉树
- 面试题整理-重建二叉树
- 剑指Offer学习之面试题6 :重建二叉树