数据结构 - 二叉树(重构 + 遍历)

 

 

  • 写在前面

昨天有同学问到我一题关于重构二叉树的问题(link),做了一下,也做个记录吧!

所谓二叉树的重构,就是给你前序和中序,或者中序和后序,让你还原这棵二叉树.

注意:给出前序和后序是不能唯一确定一棵二叉树的,证明请看这儿.

 

一.给出前序和中序,重构二叉树

一个递归的过程:

当前结点的value:每一轮根据前序的第一个元素确定当前结点值.

左子树的中序遍历数组:以当前结点的value为分界点,将中序分为左部分和右部分,左部分即为左子树的中序遍历数组.

右子树的中序遍历数组:以当前结点的value为分界点,将中序分为左部分和右部分,右部分即为右子树的中序遍历数组.

左子树的前序遍历数组:pre[1 ... i] (i为左子树的中序遍历数组的个数).

右子树的前序遍历数组:pre[i+1 ... end](i为左子树的中序遍历数组的个数).

构造出这5个值,继续递归求左右子树即可.

题目1:重建二叉树(剑指offer)

给出前序和中序,要你重建二叉树.

按照上面所说递归即可,详见代码:

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-01-03-21.09
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

/**
* Definition for binary tree
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

struct TreeNode
{
   int val;
   TreeNode *left;
   TreeNode *right;
   TreeNode(int x) : val(x),left(NULL),right(NULL) {}
};


class Solution
{
public:
   vector<int> tpr;
   vector<int> tin;
   void reBuild(int a,int b,int n,TreeNode *treeNode)
   {
       if(n==1) // leaf node
       {
           treeNode = new TreeNode(tpr[a]);
           return ;
       }
       else if(n<=0) // null node
           return ;
       int i=0;
       for(; tpr[a]!=tin[b+i]; ++i);
       TreeNode *lson,*rson;
       reBuild(a+1,b,i,lson);
       reBuild(a+1+i,b+1+i,n-i-1,rson);
       treeNode = new TreeNode(tpr[a]);
       treeNode->left=lson;
       treeNode->right=rson;
   }
   struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in)
   {
       tpr.clear();
       tin.clear();

       for(int i=0; i<pre.size(); ++i)
           tpr.push_back(pre[i]);
       for(int i=0; i<in.size(); ++i)
           tin.push_back(in[i]);

       TreeNode *root;
       int n=pre.size();
       reBuild(0,0,n,root);
       return root;
   }
};

void DFS(TreeNode *root)
{
   if(root)
   {
       cout<<(root->val)<< " ";
   }
   else return ;
   if(root->left)
       DFS(root->left);
   if(root->right)
       DFS(root->right);
}

int main()
{
   freopen("D:\\Desktop\\in.txt","r",stdin);
   int n;
   vector<int>pre;
   vector<int>in;
   while(cin>>n)
   {
       pre.clear();
       in.clear();
       for(int i=0; i<n; ++i)
       {
           int tmp;
           cin>>tmp;
           pre.push_back(tmp);
       }
       for(int i=0; i<n; ++i)
       {
           int tmp;
           cin>>tmp;
           in.push_back(tmp);
       }
       Solution a;
       TreeNode *root=a.reConstructBinaryTree(pre,in);
       DFS(root);
   }
   return 0;
}

 

题目2:HDU 1710 Binary Tree Traversals

方法一:也很简单,根据上面说的方法递归建树,然后按照后序访问输出即可.

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-01-04-18.01
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

int n;
vector<int> pr;
vector<int> in;

struct TreeNode
{
     int val;
     TreeNode *left,*right;
     TreeNode(int v):val(v),left(NULL),right(NULL){}
};

TreeNode* reBuildBinaryTree(vector<int> pr,vector<int> in)
{
     if(pr.size()==0 || in.size()==0)
           return NULL;
     int root=pr[0];
     TreeNode *node=new TreeNode(root);
     vector<int> prLeft,prRight,inLeft,inRight;
     int i=0;
     for(;pr[0]!=in[i];++i);

     for(int j=0;j!=i;++j)
           inLeft.push_back(in[j]);
     for(int j=i+1;j<in.size();++j)
           inRight.push_back(in[j]);
     for(int j=1;j<i+1;++j)
           prLeft.push_back(pr[j]);
     for(int j=i+1;j<pr.size();++j)
           prRight.push_back(pr[j]);

     node->left=reBuildBinaryTree(prLeft,inLeft);
     node->right=reBuildBinaryTree(prRight,inRight);
     return node;
}


vector<int>po;
void getPostOrder(TreeNode *root,bool flag)
{
     if(root->left)
           getPostOrder(root->left,0);
     if(root->right)
           getPostOrder(root->right,0);
     po.push_back(root->val);
}
int main()
{
     while(cin>>n)
     {
           int tmp;
           pr.clear();
           in.clear();
           po.clear();
           for(int i=0;i<n;++i)
           {
                 cin>>tmp;
                 pr.push_back(tmp);
           }
           for(int i=0;i<n;++i)
           {
                 cin>>tmp;
                 in.push_back(tmp);
           }
           TreeNode *root=reBuildBinaryTree(pr,in);
           getPostOrder(root,1);
           for(int i=0;i<n;++i)
           {
                 if(i<n-1) cout<<po[i]<<" ";
                 else cout<<po[i]<<endl;
           }
     }
     return 0;
}

 

方法二:由于题目没让重构二叉树,只让输出后序访问的顺序,因此可直接访问输出.

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-01-04-20.09
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

int n;
vector<int> pr; // pre Order
vector<int> in; // in Order
vector<int> po; // post Order

void getPostOrder(int a,int b,int n,bool flag)
{
     if(n==1)
     {
           po.push_back(pr[a]);
           return;
     }
     else if(n<=0)
           return;
     int i=0;
     for(;pr[a]!=in[b+i];++i);
     getPostOrder(a+1,b,i,false);
     getPostOrder(a+i+1,b+i+1,n-i-1,false);
     po.push_back(pr[a]);
}

int main()
{
     while(cin>>n)
     {
           pr.clear();
           in.clear();
           po.clear();
           for(int i=0;i<n;++i)
           {
                 int tmp;
                 cin>>tmp;
                 pr.push_back(tmp);
           }
           for(int i=0;i<n;++i)
           {
                 int tmp;
                 cin>>tmp;
                 in.push_back(tmp);
           }

           getPostOrder(0,0,n,true);
           for(int i=0;i<n;++i)
           {
                 if(i<n-1)
                       cout<<po[i]<<" ";
                 else cout<<po[i]<<endl;
           }
     }
     return 0;
}

 

 

 


 

二.给出后序和中序,重构二叉树

一个递归的过程:

当前结点的value:每一轮根据前序的最后一个元素确定当前结点值.

左子树的中序遍历数组:以当前结点的value为分界点,将中序分为左部分和右部分,左部分即为左子树的中序遍历数组.

右子树的中序遍历数组:以当前结点的value为分界点,将中序分为左部分和右部分,右部分即为右子树的中序遍历数组.

左子树的前序遍历数组:pre[0 ... i-1] (i为左子树的中序遍历数组的个数).

右子树的前序遍历数组:pre[i ... end-1](i为左子树的中序遍历数组的个数).

构造出这5个值,继续递归求左右子树即可.

红色部分标出的是和上面的不同点,其余都相同.

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-01-04-22.07
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);

int n;
vector<int> po;
vector<int> in;

struct TreeNode
{
     int val;
     TreeNode *left,*right;
     TreeNode(int v):val(v),left(NULL),right(NULL){}
};

TreeNode* reBuildBinaryTree(vector<int> po,vector<int> in)
{
     if(po.size()==0 || in.size()==0)
           return NULL;

     int root=po[po.size()-1];
     TreeNode* node=new TreeNode(root);
     vector<int> poLeft,poRight,inLeft,inRight;
     int i=0;
     for(;in[i]!=root;++i);

     for(int j=0;j<i;++j)
           inLeft.push_back(in[j]);
     for(int j=i+1;j<in.size();++j)
           inRight.push_back(in[j]);
     for(int j=0;j<i;++j)
           poLeft.push_back(po[j]);
     for(int j=i;j<po.size()-1;++j)
           poRight.push_back(po[j]);
     node->left=reBuildBinaryTree(poLeft,inLeft);
     node->right=reBuildBinaryTree(poRight,inRight);
     return node;

}

void print_BFS(TreeNode* root)
{
     queue<TreeNode*> q;
     q.push(root);
     while(!q.empty())
     {
           TreeNode *now=q.front();
           q.pop();
           cout<<(now->val)<<" ";
           if(now->left) q.push(now->left);
           if(now->right) q.push(now->right);
     }
}

int main()
{
    // test demo
     int a[]={7,4,2,5,8,6,3,1};
     int b[]={4,7,2,1,5,3,8,6};
     po.clear();
     in.clear();
     for(int i=0;i<8;++i)
     {
           po.push_back(a[i]);
           in.push_back(b[i]);
     }
     TreeNode *root=reBuildBinaryTree(po,in);
     print_BFS(root);
     return 0;
}

 

上一篇:带你读《少儿人工智能趣味入门动画与游戏编程一本通》之二:角色的基础:“运动”“外观”“声音”模块


下一篇:美国下注15亿美元重点搞芯片!电子复兴5年计划首批入围项目曝光