二叉树复原

描述

根据已经知的二叉树的前序序列以及中序序列,复原出相应的二叉树。

思路

根据二树的前序序列以及中序序列特点进行还原。前序序列首节点必为树的根节点,因此,在中序序列中查找定位到对应的根节点的位置。则位于中序序列中根节点所在位置的左侧节点全为树根节点的左子树上的节点;位于中序序列中根节点所在位置的右侧节点全为树根节点的右子树上的节点。然后可递归处理左、右子树即可还原。

注意:

01.根据该思路,还可以验证所输入的前序序列以及中序序列是否是合法的。只有合法的,才可以正确还原出对应的二叉树来。否则不行。

02.根据同样的思路,如果已经二叉树的中序序列以及后序序列,同样也可以还原出对应的二叉树。

具体实现编码参考如下:

 1 /******************************************************************************
 2
 3                              I‘m jacc.kim
 4
 5     CreateDate: 2017-03-20 10:37:29
 6     FileName  : RestoreBinaryTree.h
 7     Version   : 1.00
 8     Author    : jacc.kim
 9     Summary   : 根据前序记功与中序遍历结果,或中序遍历结果与后序遍历结果,重建/恢复二叉树
10
11 ******************************************************************************/
12 #pragma once
13
14 #include "JK/Common/Basic/JKDefine.h"
15
16 #include "Algorithm/AlgorithmCommon/AlgorithmDefine.h"
17
18 NS_ALGORITHM_BEGIN
19
20 //
21 // 树节点定义
22 struct BinaryTreeNode
23 {
24     int                             nValue;
25     BinaryTreeNode*                 left;
26     BinaryTreeNode*                 right;
27
28     ~BinaryTreeNode() {
29         std::cout << "destroy node: " << nValue;
30         if (nullptr != left) {
31             std::cout << " left = " << left->nValue;
32         }
33         if (nullptr != right) {
34             std::cout << " right = " << right->nValue;
35         }
36         std::cout << std::endl;
37
38         if (nullptr != left) {
39             SAFE_DELETE_NULL(left);
40         }
41         if (nullptr != right) {
42             SAFE_DELETE_NULL(right);
43         }
44     }
45
46 };//struct BinaryTreeNode
47
48 /******************************************************************************
49  * create   : (jacc.kim) [03-20-2017]
50  * summary  : class RestoreBinaryTree
51 ******************************************************************************/
52 class RestoreBinaryTree
53 {
54 public:
55     //
56     // summary     : 根据前序序列以及中序序列,重建/恢复二叉树
57     // in param    : preOrder 前序序列
58     // in param    : midOrder 中序序列
59     // in param    : nLength 长度.即:树的总节点个数
60     // return      : true 恢复成功; fasle 失败.
61     // !!!note     : 01.假设树中的任一节点值都不重复.
62     bool                            restoreBinaryTreeByPreAndMidOrder(BinaryTreeNode** ppTree, int preOrder[], int midOrder[], const int nLength);
63
64     //
65     // summary     : 根据中序序列以及后序序列,重建/恢复二叉树
66     // in param    : midOrder 中序序列
67     // in param    : postOrder 后序序列
68     // in param    : nLength 序列长度.即:序列的元素总个数.取值 [1..n].如果输入 <= 0表示没有树节点了.
69     // return      : true 恢复成功; false 恢复失败,说明输入的序列有误,并非某棵二叉树的中序及后序序列.
70     // !!!note     : 01.假设树中的任一节点值都不重复.
71     bool                            resotreBinaryTreeByMidAndPostOrder(BinaryTreeNode** ppTree, int midOrder[], int postOrder[], const int nLength);
72
73 };//class RestoreBinaryTree
74
75 NS_ALGORITHM_END
 1 #include "Algorithm/RestoreBinaryTree/RestoreBinaryTree.h"
 2
 3 NS_ALGORITHM_BEGIN
 4
 5 ///////////////////////////////////////////////////////////////////////////////
 6 // class RestoreBinaryTree
 7
 8 bool RestoreBinaryTree::restoreBinaryTreeByPreAndMidOrder(BinaryTreeNode** ppTree, int preOrder[], int midOrder[], const int nLength) {
 9     if (nullptr == ppTree) {
10         return false;   // 输入有误
11     }
12     *ppTree = nullptr;
13     if (nLength <= 0) {
14         return false;   // 输入有误.
15     }
16     BinaryTreeNode* pTreeNode = new BinaryTreeNode();
17     if (nullptr == pTreeNode) {
18         return false;   //
19     }
20     *ppTree = pTreeNode;
21     pTreeNode->nValue = preOrder[0];
22     pTreeNode->left = nullptr;
23     pTreeNode->right = nullptr;
24
25     // 在 midOrder 中定位根节点位置
26     int* pRootNodePos = midOrder;
27     while (pRootNodePos != midOrder + nLength && *pRootNodePos != preOrder[0]) {
28         ++pRootNodePos;
29     }
30     if (pRootNodePos == midOrder + nLength) {
31         SAFE_DELETE_NULL(*ppTree);
32         return false;   // 输入有误
33     }
34
35     const int nLeftChildTreeNodeCount = pRootNodePos - midOrder;
36     const int nRightChildTreeNodeCount = nLength - nLeftChildTreeNodeCount - 1;
37
38     if (nLeftChildTreeNodeCount > 0) {
39         if (!this->restoreBinaryTreeByPreAndMidOrder(&(*ppTree)->left, preOrder + 1, midOrder, nLeftChildTreeNodeCount)) {
40             SAFE_DELETE_NULL(*ppTree);
41             return false;
42         }
43     }
44     if (nRightChildTreeNodeCount > 0) {
45         if (!this->restoreBinaryTreeByPreAndMidOrder(&(*ppTree)->right, preOrder + nLeftChildTreeNodeCount + 1, pRootNodePos + 1, nRightChildTreeNodeCount)) {
46             SAFE_DELETE_NULL(*ppTree);
47             return false;
48         }
49     }
50     return true;
51 }
52
53 bool RestoreBinaryTree::resotreBinaryTreeByMidAndPostOrder(BinaryTreeNode** ppTree, int midOrder[], int postOrder[], const int nLength) {
54     if (nullptr == ppTree) {
55         return false;   // 输入有误.
56     }
57     *ppTree = nullptr;  // init
58     if (nLength <= 0) {
59         return true;    // 没有数据,就不处理了,即:返回一棵空树即可.因此,返回true
60     }
61     BinaryTreeNode* pTreeNode = new BinaryTreeNode();
62     if (nullptr == pTreeNode) {
63         return false;   // there is no enough memory for restore binary tree.
64     }
65     *ppTree = pTreeNode;
66     pTreeNode->nValue = postOrder[nLength - 1];
67     pTreeNode->left = nullptr;
68     pTreeNode->right = nullptr;
69     // 定位左、右子树分界线
70     int* pRootNodePosInMidOrder = midOrder;
71     while (pRootNodePosInMidOrder != midOrder + nLength && *pRootNodePosInMidOrder != postOrder[nLength - 1]) {
72         ++pRootNodePosInMidOrder;
73     }
74     if (pRootNodePosInMidOrder == midOrder + nLength) {
75         SAFE_DELETE_NULL(*ppTree);
76         return false;   // 输入有误.
77     }
78     const int nLeftChildTreeLength = pRootNodePosInMidOrder - midOrder;
79     const int nRightChildTreeLength = nLength - nLeftChildTreeLength - 1;
80
81     if (nLeftChildTreeLength > 0) {
82         if (!this->resotreBinaryTreeByMidAndPostOrder(&(*ppTree)->left, midOrder, postOrder, nLeftChildTreeLength)) {
83             SAFE_DELETE_NULL(*ppTree);
84             return false;
85         }
86     }
87     if (nRightChildTreeLength > 0) {
88         if (!this->resotreBinaryTreeByMidAndPostOrder(&(*ppTree)->right, pRootNodePosInMidOrder + 1, postOrder + nLeftChildTreeLength, nRightChildTreeLength)) {
89             SAFE_DELETE_NULL(*ppTree);
90             return false;
91         }
92     }
93     return true;
94 }
95
96 NS_ALGORITHM_END

测试用例及结果

 1 int _tmain(int argc, _TCHAR* argv[])
 2 {
 3
 4     //nsalgorithm::ValidateProjectConfig::validate("log/RestoreBinaryTree/testlog");
 5
 6     {
 7         std::cout << "Input correct test data" << std::endl;
 8         std::cout << "-----------------------" << std::endl << std::endl;
 9         nsalgorithm::RestoreBinaryTree restoreBinaryTree;
10         const int nNodeMax = 6;
11         int preOrder[nNodeMax] = { 1, 2, 4, 5, 3, 6 };
12         int midOrder[nNodeMax] = { 4, 2, 5, 1, 6, 3 };
13         int postOrder[nNodeMax] = { 4, 5, 2, 6, 3, 1 };
14
15         std::cout << "use preorder & midorder:" << std::endl;
16         nsalgorithm::BinaryTreeNode* pTree1 = nullptr;
17         const auto bIsSuccess = restoreBinaryTree.restoreBinaryTreeByPreAndMidOrder(&pTree1, preOrder, midOrder, nNodeMax);
18         if (!bIsSuccess) {
19             int asfasf = 0;     // 不会进入该分支.因为输入测试数据全都合法
20         }
21         SAFE_DELETE_NULL(pTree1);
22
23         std::cout << std::endl << "use mirorder & postorder:" << std::endl;
24
25         nsalgorithm::BinaryTreeNode* pTree2 = nullptr;
26         const auto bIsSuccess2 = restoreBinaryTree.resotreBinaryTreeByMidAndPostOrder(&pTree2, midOrder, postOrder, nNodeMax);
27         if (!bIsSuccess2) {
28             int asfasf = 0;     // 不会进入该分支.因为输入测试数据全都合法
29         }
30         SAFE_DELETE_NULL(pTree2);
31
32         std::cout << std::endl << "=========================" << std::endl;
33     }
34
35     {
36         std::cout << "Input incorrect test data" << std::endl;
37         std::cout << "-----------------------" << std::endl << std::endl;
38         nsalgorithm::RestoreBinaryTree restoreBinaryTree;
39         const int nNodeMax = 6;
40         int preOrder[nNodeMax] = { 1, 2, 4, 5, 3, 6 };
41         int midOrder[nNodeMax] = { 4, 2, 9, 1, 6, 3 };  // 将第3个位置的正确数字 5 改成 9 进行测试
42         int postOrder[nNodeMax] = { 4, 5, 2, 6, 3, 1 };
43
44         std::cout << "use preorder & midorder:" << std::endl;
45         nsalgorithm::BinaryTreeNode* pTree1 = nullptr;
46         const auto bIsSuccess = restoreBinaryTree.restoreBinaryTreeByPreAndMidOrder(&pTree1, preOrder, midOrder, nNodeMax);
47         if (!bIsSuccess) {
48             int asfasf = 0;     // 会进入该分支.输入的中序序列测试数据有问题,无法正确重建二叉树
49         }
50         SAFE_DELETE_NULL(pTree1);
51
52         std::cout << std::endl << "use mirorder & postorder:" << std::endl;
53
54         nsalgorithm::BinaryTreeNode* pTree2 = nullptr;
55         const auto bIsSuccess2 = restoreBinaryTree.resotreBinaryTreeByMidAndPostOrder(&pTree2, midOrder, postOrder, nNodeMax);
56         if (!bIsSuccess2) {
57             int asfasf = 0;     // 会进入该分支.输入的中序序列测试数据有问题,无法正确重建二叉树
58         }
59         SAFE_DELETE_NULL(pTree2);
60
61         std::cout << std::endl << "=========================" << std::endl;
62     }
63
64     {
65         std::cout << "Input incorrect test data" << std::endl;
66         std::cout << "-----------------------" << std::endl << std::endl;
67         nsalgorithm::RestoreBinaryTree restoreBinaryTree;
68         const int nNodeMax = 6;
69         int preOrder[nNodeMax] = { 1, 2, 9, 5, 3, 6 };  // 将第3个位置的正确数字 4 改成 9 进行测试
70         int midOrder[nNodeMax] = { 4, 2, 5, 1, 6, 3 };
71         int postOrder[nNodeMax] = { 4, 5, 2, 6, 3, 1 };
72
73         std::cout << "use preorder & midorder:" << std::endl;
74         nsalgorithm::BinaryTreeNode* pTree1 = nullptr;
75         const auto bIsSuccess = restoreBinaryTree.restoreBinaryTreeByPreAndMidOrder(&pTree1, preOrder, midOrder, nNodeMax);
76         if (!bIsSuccess) {
77             int asfasf = 0;     // 会进入该分支.输入的前序序列测试数据有问题,无法正确重建二叉树
78         }
79         SAFE_DELETE_NULL(pTree1);
80
81         std::cout << std::endl << "use mirorder & postorder:" << std::endl;
82
83         nsalgorithm::BinaryTreeNode* pTree2 = nullptr;
84         const auto bIsSuccess2 = restoreBinaryTree.resotreBinaryTreeByMidAndPostOrder(&pTree2, midOrder, postOrder, nNodeMax);
85         if (!bIsSuccess2) {
86             int asfasf = 0;     // 不会进入该分支.因为输入测试数据全都合法
87         }
88         SAFE_DELETE_NULL(pTree2);
89
90         std::cout << std::endl << "=========================" << std::endl;
91     }
92
93     system("pause");
94     return 0;
95 }

时间: 2024-10-23 03:25:26

二叉树复原的相关文章

复原二叉树

1.由(preorder+inorder)复原 /* * preorder:先序遍历数组 * ps,pe:先序数组的首元素和末元素的索引 * inod:中序遍历数组 * is,ie:中序数组的首元素和末元素的索引 */ public class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { return buildBT(preorder,0,preorder.length-1,inorder,0,ino

poj2255 (二叉树遍历)

poj2255 二叉树遍历 Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Little Valentine liked playing with binary trees very much. Her favorite game was constructing randomly looking binary trees with capital letters in the

二叉树的递归插入【Java实现】

C++中由于有指针的存在,可以让二叉树节点指针的指针作为插入函数的实参,在函数体内通过*操作实现对真实节点指针.节点左孩子指针.节点右孩子指针的改变,这样很容易使用递归将大树问题转化到小树问题.但在JAVA中,由于没有指针只有引用,如果需要递归实现二叉树的元素插入,需要对节点进行包装,同时由于递归时需要将大树问题递归到子树,包装类中的节点需要改变,但因为最后需要的是根节点,所以根节点需要备份,在递归完成后复原.下面是实现代码: 1 package test; 2 3 4 5 public cla

[LeetCode] Recover Binary Search Tree 复原二叉搜索树

Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing its structure. Note:A solution using O(n) space is pretty straight forward. Could you devise a constant space solution? confused what "{1,#,2,3}"

红黑树一:从二叉树、2-3树到红黑树,一步步讲解红黑树的来源

目录 1 引言 2 从二叉查找树到红黑树的演变 2.1 二叉查找树 2.2 平衡二叉查找树 2.3 2-3树 2.4 红黑树 1 引言 RB-Tree,即红黑树,它的定义如下: 这是一颗二叉树,且每个节点要么是红色.要么是黑色 根节点是黑色 叶子节点也是黑色的,且叶子节点不存储数据,即叶子节点是nil空节点 不能出现连续的红色节点,即相邻的红色节点必须被黑色节点隔开 任何一个节点到达其任意一个叶子节点均包含相同数目的黑色节点 单看上面的定义,大家肯定跟我一样一头雾水,别急,下面我们从最简单的二叉

C#实现二叉树的遍历

C#实现二叉树的前序.中序.后序遍历. public class BinaryTreeNode     {         int value;         BinaryTreeNode left;         BinaryTreeNode right;         /// <summary>         /// 前序遍历         /// </summary>         /// <param name="tree">&l

【树4】二叉树的遍历

简介 遍历二叉树就是按照某种顺序,将树中的结点都枚举一遍,且每个结点仅仅访问一次.因为树不是线性的结构,遍历不像线性表那样简单,因此他的遍历需要特点的算法来完成. 从某种角度讲,对二叉树的遍历就是将树形结构转换为线性结构的操作. 二叉树的遍历方法主要有如下几种: 先序遍历:先访问root结点,再先序遍历左子树,再先序遍历右子树. 中序遍历:先中序遍历左子树,再访问root结点,再中序遍历右子树. 后序遍历:先后序遍历左子树,再后序遍历右子树,再访问root结点. 层遍历:从上到下,从左到右,一层

按之字形顺序打印二叉树

题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推 /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */ class Solution { public: vector<vect

【数据算法】Java实现二叉树存储以及遍历

二叉树在java中我们使用数组的形式保存原数据,这个数组作为二叉树的数据来源,后续对数组中的数据进行节点化操作. 步骤就是原数据:数组 节点化数据:定义 Node节点对象 存储节点对象:通过LinkedList保存Node节点对象 在操作过程中我们需要将当前结点和前一节点.后一节点进行关系绑定 package tree; import java.util.LinkedList; import java.util.List; /** * 功能:把一个数组的值存入二叉树中,然后进行3种方式的遍历 *