一、题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不包含重复的数字。
例如,输入前序遍历序列[1, 2, 4, 7, 3, 5, 6, 8]和中序遍历序列[4, 7, 2, 1, 5, 3, 8, 6],则重建如下图所示的二叉树并输出它的头结点:
二、解析
根据前序、中序遍历的特性和上面的图形能得到的结论:
- 前序遍历的第一个元素就是树的根节点。
- 根节点左边的元素就是左子树,根右边的就是右子树。
图片描述:
基于这两个特性就可以通过以下方式来构建出一颗二叉树:从前序遍历中确认根节点,再到中序遍历中找到定位到这个根节点,这样就可以拿到对应的左子树和右子树了。然后再按照相同的方式分别得到左右子树的子树,那么整个二叉树就可以构建起来了。
三、代码实现
二叉树节点定义:
1 2 3 4 5 6 7 8 9 |
template<typename T> class tree_node { friend class bin_tree<T>; tree_node(const T &data) : data(data), lchild(nullptr), rchild(nullptr) {} private: T data; tree_node *lchild; tree_node *rchild; } |
二叉树定义:
1 2 3 4 5 |
class bin_tree { public: bin_tree() : root(nullptr) {} tree_node<T> *root; }; |
在二叉树类中实现通过前序遍历和中序遍历构造二叉树的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
/* * 根据前序和中序遍历序列构造一个二叉树 * @pre_order 前序遍历序列 * @in_order 中序遍历序列 * @len 序列长度 */ void construct(const T pre_order[], const T in_order[], const unsigned int len) { if (len < 1) return; this->root = construct_core(pre_order, pre_order + len - 1, in_order, in_order + len - 1); } /* * 通过前序遍列和中序遍历的结果构建二叉树 * 前序遍历序列[pre_order_start, pre_order_end],中序遍历序列[in_order_start, in_order_end] * @pre_order_start 前序遍历的开始位置 * @pre_order_end 前序遍历的结束位置 * @in_order_start 中序遍历的开始位置 * @in_order_end 中序遍历的结束位置 */ tree_node<T> *construct_core(const T *pre_order_start, const T *pre_order_end, const T *in_order_start, const T *in_order_end) { // 遍历指针 const T *cursor; // 前序遍历序列中左子树的结束位置 const T *lchild_end; // 左子树的长度 unsigned int lchild_len; // 根节点 tree_node<T> *root = nullptr;; // 前序遍历的首元素即为树根 root = new tree_node<T>(pre_order_start[0]); // 如果前序遍历的头和尾相等,说明只有一个元素了,返回当前元素 if (pre_order_start == pre_order_end) { // 下面是简单的判断输入参数是否合法 // 如果只有一个元素了,前序和中序的遍历结果是相同的 if (in_order_start == in_order_end && *in_order_start == *pre_order_start) return root; else // 输入有问题 throw "invalid input"; } // 在中序遍历中找到根节点 cursor = in_order_start; while (cursor < in_order_end && *cursor != root->data) cursor++; // 匹配到中序遍历的最后一个元素了还没有找到,说明输入不合法 if (cursor == in_order_end && *cursor != root->data) throw "invalid input"; lchild_len = cursor - in_order_start; lchild_end = pre_order_start + lchild_len; // 递归获取左子树 if (lchild_len > 0) { root->lchild = construct_core(pre_order_start + 1, lchild_end, in_order_start, cursor - 1); } // 递归获取右子树 if (lchild_len < pre_order_end - pre_order_start) { root->rchild = construct_core(lchild_end + 1, pre_order_end, cursor + 1, in_order_end); } return root; } |
四、单元测试
单元测试覆盖以下几点:
- 树为空
- 树只有一个节点
- 完全二叉树
- 满二叉树
- 不完全二叉树
4.1 树为空
1 2 3 4 5 6 7 8 9 10 11 12 |
/* * 测试:通过前序和中序便利序列构造二叉树 * 案例:二叉树包含一个节点 */ TEST(construct_by_pre_order_and_in_order, one_node) { bin_tree<int> tree; int data[1] = {1}; tree.construct(data, data, 1); EXPECT_TRUE(tree.get_root()); EXPECT_FALSE(tree.get_root()->get_lchild()); EXPECT_FALSE(tree.get_root()->get_rchild()); } |
4.2 树只有一个节点
1 2 3 4 5 6 7 8 9 10 11 12 |
/* * 测试:通过前序和中序便利序列构造二叉树 * 案例:二叉树包含一个节点 */ TEST(construct_by_pre_order_and_in_order, one_node) { bin_tree<int> tree; int data[1] = {1}; tree.construct(data, data, 1); EXPECT_TRUE(tree.get_root()); EXPECT_FALSE(tree.get_root()->get_lchild()); EXPECT_FALSE(tree.get_root()->get_rchild()); } |
4.3 完全二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/* * 测试:通过前序和中序便利序列构造二叉树 * 案例:完全二叉树测试 * 1 * 2 3 * 4 5 */ TEST(construct_by_pre_order_and_in_order, complete_bin_tree) { int pre_order[7] = {1, 2, 4, 5, 3}; int in_order[7] = {4, 2, 5, 1, 3}; bin_tree<int> tree; const tree_node<int> *root, *node; tree.construct(pre_order, in_order, 5); root = tree.get_root(); EXPECT_TRUE(root); EXPECT_EQ(root->get_data(), 1); EXPECT_TRUE(root->get_lchild()); EXPECT_TRUE(root->get_rchild()); EXPECT_EQ(root->get_lchild()->get_data(), 2); EXPECT_EQ(root->get_rchild()->get_data(), 3); node = root->get_lchild(); // -> 节点2 // 检查子节点 EXPECT_TRUE(node->get_lchild()); EXPECT_TRUE(node->get_rchild()); EXPECT_EQ(node->get_lchild()->get_data(), 4); EXPECT_EQ(node->get_rchild()->get_data(), 5); // 检查子节点的子节点 EXPECT_FALSE(node->get_lchild()->get_lchild()); EXPECT_FALSE(node->get_lchild()->get_rchild()); EXPECT_FALSE(node->get_rchild()->get_lchild()); EXPECT_FALSE(node->get_rchild()->get_rchild()); node = root->get_rchild(); // -> 节点3 // 检查子节点 EXPECT_FALSE(node->get_lchild()); EXPECT_FALSE(node->get_rchild()); } |
4.4 满二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/* * 测试:通过前序和中序便利序列构造二叉树 * 案例:满二叉树测试 * 1 * 2 3 * 4 5 6 7 */ TEST(construct_by_pre_order_and_in_order, full_bin_tree) { int pre_order[7] = {1, 2, 4, 5, 3, 6, 7}; int in_order[7] = {4, 2, 5, 1, 6, 3, 7}; bin_tree<int> tree; const tree_node<int> *root, *node; tree.construct(pre_order, in_order, 7); root = tree.get_root(); EXPECT_TRUE(root); EXPECT_EQ(root->get_data(), 1); EXPECT_TRUE(root->get_lchild()); EXPECT_TRUE(root->get_rchild()); EXPECT_EQ(root->get_lchild()->get_data(), 2); EXPECT_EQ(root->get_rchild()->get_data(), 3); node = root->get_lchild(); // -> 节点2 // 检查子节点 EXPECT_TRUE(node->get_lchild()); EXPECT_TRUE(node->get_rchild()); EXPECT_EQ(node->get_lchild()->get_data(), 4); EXPECT_EQ(node->get_rchild()->get_data(), 5); // 检查子节点的子节点 EXPECT_FALSE(node->get_lchild()->get_lchild()); EXPECT_FALSE(node->get_lchild()->get_rchild()); EXPECT_FALSE(node->get_rchild()->get_lchild()); EXPECT_FALSE(node->get_rchild()->get_rchild()); node = root->get_rchild(); // -> 节点3 // 检查子节点 EXPECT_TRUE(node->get_lchild()); EXPECT_TRUE(node->get_rchild()); EXPECT_EQ(node->get_lchild()->get_data(), 6); EXPECT_EQ(node->get_rchild()->get_data(), 7); // 检查子节点的子节点 EXPECT_FALSE(node->get_lchild()->get_lchild()); EXPECT_FALSE(node->get_lchild()->get_rchild()); EXPECT_FALSE(node->get_rchild()->get_lchild()); EXPECT_FALSE(node->get_rchild()->get_rchild()); } |
4.5 非完全二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/* * 测试:通过前序和中序便利序列构造二叉树 * 案例:普通二叉树测试 * 1 * 2 3 * 5 6 */ TEST(construct_by_pre_order_and_in_order, normal_bin_tree) { int pre_order[7] = {1, 2, 5, 3, 6}; int in_order[7] = {2, 5, 1, 6, 3}; bin_tree<int> tree; const tree_node<int> *root, *node; tree.construct(pre_order, in_order, 5); root = tree.get_root(); EXPECT_TRUE(root); EXPECT_EQ(root->get_data(), 1); EXPECT_TRUE(root->get_lchild()); EXPECT_TRUE(root->get_rchild()); EXPECT_EQ(root->get_lchild()->get_data(), 2); EXPECT_EQ(root->get_rchild()->get_data(), 3); node = root->get_lchild(); // -> 节点2 // 检查子节点 EXPECT_FALSE(node->get_lchild()); EXPECT_TRUE(node->get_rchild()); EXPECT_EQ(node->get_rchild()->get_data(), 5); // 检查子节点的子节点 EXPECT_FALSE(node->get_rchild()->get_lchild()); EXPECT_FALSE(node->get_rchild()->get_rchild()); node = root->get_rchild(); // -> 节点3 // 检查子节点 EXPECT_TRUE(node->get_lchild()); EXPECT_FALSE(node->get_rchild()); // 左子节点为6,右子节点为空 EXPECT_EQ(node->get_lchild()->get_data(), 6); // 检查子节点的子节点 EXPECT_FALSE(node->get_lchild()->get_lchild()); EXPECT_FALSE(node->get_lchild()->get_rchild()); } |
评论