九度OJ_1385:重建二叉树

题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。

输入:

输入可能包含多个测试样例,对于每个测试案例,

输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点个数。

输入的第二行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的前序遍历序列。

输入的第三行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的中序遍历序列。

输出:

对应每个测试案例,输出一行:

如果题目中所给的前序和中序遍历序列能构成一棵二叉树,则输出n个整数,代表二叉树的后序遍历序列,每个元素后面都有空格。

如果题目中所给的前序和中序遍历序列不能构成一棵二叉树,则输出”No

#include
      
      
       
         
#define MAX 1001  
   
// 构建二叉树的结点  
typedef struct Node  
{  
   int data;            // 数据域  
   Node * lChild;       // 左子树  
   Node * rChild;       // 右子树  
}BinaryTreeNode;  
BinaryTreeNode biTreeNode[MAX];  
   
bool canRebuildBinaryTree; // 判断能否重构二叉树  
int preOrder[MAX];      // 二叉树的前序遍历序列  
int inOrder[MAX];       // 二叉树的中序遍历序列  
   
/** 
* 初始化二叉树中的每个结点,将每个结点都看成是只有一个根结点而左右子树都为NULL的二叉树 
* @param int n  二叉树的结点数 
* @return void 
*/  
void initBinaryTree(int n)  
{  
  int i;  
  canRebuildBinaryTree = true;  
  for(i = 0;i < n;i++)  
  {  
    biTreeNode[i].data = preOrder[i];  // 将前序遍历序列中的元素依次赋值给二叉树中的结点  
    biTreeNode[i].lChild = NULL;  
    biTreeNode[i].rChild = NULL;  
  }  
}  
   
/** 
* 重构二叉树 
* @param int beginPreOrder  前序遍历序列的起点 
* @param int endPreOrder  前序遍历序列的终点 
* @param int beginInOrder  中序遍历序列的起点 
* @param int endInOrder  中序遍历序列的终点 
* @return void 
*/  
void reBuildBinaryTree(int beginPreOrder,int endPreOrder,int beginInOrder,int endInOrder)  
{  
   int i;  
   int partion = -1;     // 前序遍历序列第一个结点在中序遍历序列中的相对位置  
   bool isBeginPreOrderinInOrder = false; // 判断前序遍历序列中的第一个结点是否在中序遍历序列中,以此来判断是否能构成二叉树  
   // 遍历二叉树的中序遍历序列,得到根结点在中序遍历序列中的位置  
   for(i = beginInOrder;i <= endInOrder;i++)  
   {  
       if(preOrder[beginPreOrder] == inOrder[i])  
       {  
          partion = i - beginInOrder;  
          isBeginPreOrderinInOrder = true;  
          break;  
       }  
   }  
   if(false == isBeginPreOrderinInOrder)  
   {  
       canRebuildBinaryTree = false;  
       return;  
   }  
   else  
   {  
       // 以partion为分隔标识  
       // 将前序遍历序列分为[beginPreOrder + 1,beginPreOrder + partion]  
       // 和[beginPreOrder + partion + 1,endPreOrder]两个子序列  
       // 将中序遍历序列分为[beginInOrder,beginInOrder + partion - 1]  
       // 和[beginInOrder + partion + 1,endInOrder]两个子序列  
   
       // 用前序遍历子序列[beginPreOrder + 1,beginPreOrder + partion]  
       // 和中序遍历子序列[beginInOrder,beginInOrder + partion - 1]重构左子树  
       if(beginPreOrder + 1 <= beginPreOrder + partion && beginInOrder <= beginInOrder + partion - 1)  
       {  
           biTreeNode[beginPreOrder].lChild = &biTreeNode[beginPreOrder + 1];  
           reBuildBinaryTree(beginPreOrder + 1,beginPreOrder + partion,beginInOrder,beginInOrder + partion - 1);  
       }  
       // 用前序遍历子序列[beginPreOrder + partion + 1,endPreOrder]  
       // 和中序遍历子序列[beginInOrder + partion + 1,endInOrder]重构右子树  
       if(beginPreOrder + partion + 1 <= endPreOrder && beginInOrder + partion + 1 <= endInOrder)  
       {  
           biTreeNode[beginPreOrder].rChild = &biTreeNode[beginPreOrder + partion + 1];  
           reBuildBinaryTree(beginPreOrder + partion + 1,endPreOrder,beginInOrder + partion + 1,endInOrder);  
       }  
   }  
}  
   
/** 
* 后序遍历二叉树 
* @param BinaryTreeNode * root  后序遍历的根结点 
* @return void 
*/  
void postOrder(BinaryTreeNode * root)  
{  
  if(NULL == root)  
    return;  
  else  
  {  
     postOrder(root -> lChild);  
     postOrder(root -> rChild);  
     printf("%d ",root -> data);  
  }  
}  
   
int main()  
{  
    int n;  
    int i;  
    while(EOF != scanf("%d",&n))  
    {  
      for(i = 0;i < n;i++)  
      {  
          scanf("%d",&preOrder[i]);  
      }  
      for(i = 0;i < n;i++)  
      {  
          scanf("%d",&inOrder[i]);  
      }  
      initBinaryTree(n);  
      reBuildBinaryTree(0,n - 1,0,n - 1);  
      if(false == canRebuildBinaryTree)  
         printf("No\n");  
      else  
      {  
         postOrder(&biTreeNode[0]); //因为 biTreeNode[0].data == preOrder[0],所以biTreeNode[0]是重构二叉树的根结点  
         printf("\n");  
      }  
    }  
    return 0;  
}  
      
      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值