根据层次遍历和中序遍历的结果还原一颗二叉树

此文件描述了根据层次遍历,中序遍历的结果来还原二叉树的算法
我们先分别给出一个层次遍历,和一个中序遍历的结果字符串
 层次  A B C D E F G
 中序  D B A F E G C
其对应的二叉树是:
       A
     /  /
     B  C
     /  /
     D  E
       / /
       F G
接下来详细讲解如果还原这棵二叉树的步骤,我用LEV代表层次遍历
MID代表中序遍历。然后我们还需要一个HLP数组用来存放节点指针,
其长度和层次/中序遍历字符串长度一样,并且其对应于中序遍历字
符串,我们会在下面看到。

(0)起始状态
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  0  0  0  0  0  0  0
L    0  0  0  0  0  0  0
R    0  0  0  0  0  0  0
在这里,HLP存放的是节点指针,并且全都初始化为0,这里的L/R代表
了该节点是否有左/右孩子。在下面注意HLP和MID的对应关系。
(1) [A]BCDEFG
 我们查找A在MID中的位置,创建一个节点到对应位置,初创建的节
 点没有左右孩子。
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  0  0  A  0  0  0  0
L    0  0  0  0  0  0  0
R    0  0  0  0  0  0  0
(2) A[B]CDEFG
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  0  B  A  0  0  0  0
L    0  0  0  0  0  0  0
R    0  0  0  0  0  0  0
然后从B的左面开始找有没有非0的指针,在这里我们没有找到
然后从B的右边开始找有没有非0的指针,找到了A
发现A没有左孩子,令B为A的左孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  0  B  A  0  0  0  0
L    0  0  X  0  0  0  0
R    0  0  0  0  0  0  0
(3) AB[C]DEFG
同上面步骤,发现C是A的右孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  0  B  A  0  0  0  C
L    0  0  X  0  0  0  0
R    0  0  X  0  0  0  0
(4) ABC[D]EFG
同上,发现D是B的左孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  D  B  A  0  0  0  C
L    0  X  X  0  0  0  0
R    0  0  X  0  0  0  0
(5) ABCD[E]FG
这里有些不同,因为E向左找发现A的已经有了右孩子,所它必须向
右找,结果发现E是C的左孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  D  B  A  0  E  0  C
L    0  X  X  0  0  0  X
R    0  0  X  0  0  0  0
(6) ABCDE[F]G
同上,F做不了A的右孩子,只能做了E的左孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  D  B  A  F  E  0  C
L    0  X  X  0  X  0  X
R    0  0  X  0  0  0  0
(7) ABCDEF[G]
G向左找,发现G可以做E的右孩子
同上,F做不了A的右孩子,只能做了E的左孩子
     0  1  2  3  4  5  6
MID  D  B  A  F  E  G  C
HLP  D  B  A  F  E  G  C
L    0  X  X  0  X  0  X
R    0  0  X  0  X  0  0

    到此为止ABCDEFG的关系都已经建立好了,二叉树还原完成。
至于为什么我们一定要先从左开始找,然后再向右找,也许是因为
二叉树的中序遍历它本身就是从左到右的吧,具体没有深究过。
    这个算法同样适用于前序-中序,后序-中序的二叉树还原。但是
使用这个算法你会发现需要申请与节点相同数量的临时空间,如果这
个二叉树很大似乎会不太方便。而我的另外的前序-中序,后序-中序
的二叉树还原算法所需要的临时空间的最大数目是二叉树的层次数。
一个255个元素的满二叉树,层次为8,临时空间至多需要8,显然空间
上比较优惠。
    不过话说回来,我所申请的空间最后都变成了二叉树,似乎也没有
什么不妥。
下面是算法C++表示

  1. #include 
  2. #include 
  3. #include 
  4. #include 
  5. using namespace std;
  6. struct TreeNode {
  7.     char       data;
  8.     TreeNode*   lChild;
  9.     TreeNode*   rChild;
  10. public:
  11.     TreeNode(char c) : data(c), lChild(0), rChild(0) { }
  12. };
  13. //层次-中序二叉树还原 
  14. void Lev_Mid_Restore(string lev, string mid, TreeNode*& result) {
  15.     const int size = lev.size();
  16.     TreeNode* helper[size];
  17.     for(int i = 0; i < size; i++)
  18.         helper[i] = 0;
  19.     /*            0  1  2  3  4  5  6  7  8
  20.         helper    0  0  0  0  A  0  0  0  0
  21.         lChild    0  0  0  0  0  0  0  0  0
  22.         rChild    0  0  0  0  0  0  0  0  0
  23.     */
  24.     bool success = false;
  25.     result = new TreeNode(lev[0]);
  26.     int mi = mid.find(lev[0]);
  27.     helper[mi] = result;
  28.     
  29.     for(int i = 1; i < lev.size(); i++) {
  30.         success = false;
  31.         mi = mid.find(lev[i]);
  32.         helper[mi] = new TreeNode(lev[i]);  //把这个节点放到对应的数组位置中 
  33.         /*从当前节点X的左边开始找,如果找到一个非0的节点Y,
  34.           就判断其右孩子是否为空,如果为空,则X是Y的右孩子,并且孩子配对成功,
  35.           接下来就不需要再向右找了。 
  36.           如果Y已经有右孩子了,则从节点X的右边开始找 
  37.         */ 
  38.         for(int p = mi - 1; p >= 0; p--) {
  39.             if(helper[p] != 0) {
  40.                 if(helper[p]->rChild == 0) {
  41.                     helper[p]->rChild = helper[mi];
  42.                     success = true;
  43.                 }
  44.                 break;
  45.             }
  46.         }
  47.         if(success) {
  48.             continue;
  49.         }
  50.         /*从当前节点X的右边还是找,如果找到一个非0的节点Y
  51.           判断其左孩子是否为空,如果为空,则X是Y的左孩子
  52.           如果Y已经有左孩子了,则说明这个中序/层次遍历序列有问题
  53.         */
  54.         for(int p = mi + 1; p < size; p++) {
  55.             if(helper[p] != 0) {
  56.                 if(helper[p]->lChild == 0) {
  57.                     helper[p]->lChild = helper[mi];
  58.                     success = true;
  59.                 }
  60.                 break;
  61.             }
  62.         }
  63.         //因为既然到了这一步,还没有配对成功,就说明给的中序/层次遍历序列
  64.         //有问题 
  65.         if(!success) {
  66.             cout << "error: " << lev[i] << endl;
  67.             break;
  68.         }
  69.     }
  70. }
  71. int main() {
  72.     void inorderTraversal(TreeNode* pTree);
  73.     void levelorderTraversal(TreeNode* pTree);
  74.     void Lev_Mid_Restore(string lev, string mid, TreeNode*& result);
  75.     /*                 A
  76.                     /      /
  77.                    B        C
  78.                  /   /    /   /
  79.                 D    E    F    G
  80.                / /  / /  / /  / /
  81.                H I  J K  M N  O P
  82.     */
  83.     string Levorder1 = "ABCDEFGHIJKMNOP";
  84.     string Midorder1 = "HDIBJEKAMFNCOGP";
  85.     
  86.     string Levorder2 = "ABCDEFG";
  87.     string Midorder2 = "BDAFEGC";
  88.     TreeNode* res = 0;
  89.     Lev_Mid_Restore(Levorder1, Midorder1, res);
  90.     inorderTraversal(res);  
  91.     levelorderTraversal(res);
  92.     
  93.     Lev_Mid_Restore(Levorder2, Midorder2, res);
  94.     inorderTraversal(res);  
  95.     levelorderTraversal(res);   
  96.     
  97.     cin.get();
  98. }
  99. //中序遍历 
  100. void inorderTraversal(TreeNode* pTree) {
  101.     stack treeStack;
  102.     do {
  103.         while(pTree != 0) {
  104.             treeStack.push(pTree);
  105.             pTree = pTree->lChild;
  106.         }
  107.         if(!treeStack.empty()) {
  108.             pTree = treeStack.top();
  109.             treeStack.pop();
  110.             cout << pTree->data;
  111.             pTree = pTree->rChild;
  112.         }
  113.     }while(!treeStack.empty() || pTree != 0);
  114.     cout << endl;
  115. }
  116. //层次遍历 
  117. void levelorderTraversal(TreeNode* pTree) {
  118.     queue treeQueue;
  119.     treeQueue.push(pTree);
  120.     while(!treeQueue.empty()) {
  121.         cout << treeQueue.front()->data;
  122.         TreeNode* lChild = treeQueue.front()->lChild;
  123.         TreeNode* rChild = treeQueue.front()->rChild;
  124.         if(lChild != 0) {
  125.             treeQueue.push(lChild);
  126.         }
  127.         if(rChild != 0) {
  128.             treeQueue.push(rChild);
  129.         }
  130.         treeQueue.pop();
  131.     }
  132.     cout << endl;
  133. }

你可能感兴趣的:(算法)