重建二叉树

http://www.cnblogs.com/flyoung2008/archive/2011/08/16/2141579.html

中序和后序也能重构------------

前序和后序好像不能重构----没找到资料

已只二叉树的前序和中序遍历,要求构建出完整的二叉树

           如前序遍历为:a b d c e f

           中序遍历为:d b a e c f

           由于前序遍历先访问的是根节点所以整棵树的根节点是a

           中序遍历中,先访问左子树,再访问右子树,所以d b 是左子树,e c f 是右子树

           如此递归下去,可以找到整棵树的结构

#include <iostream>

#define TREELEN 6

using namespace std;

struct NODE {

    NODE * pLeft;

    NODE * pRight;

    char chValue;

};

 

void ReBuild(char * pPreOrder , char * pInorder, int nTreeLen, NODE * * pRoot){

    if(pPreOrder == NULL || pInorder == NULL)//两个数组不为空

    return ;

    NODE * pTemp=new NODE;

    pTemp->chValue=*pPreOrder;//前序遍历的首节点即时根节点

    pTemp->pLeft=NULL;

    pTemp->pRight=NULL;

    if(*pRoot == NULL)//原来的根节点不存在,就把temp给pRoot

    *pRoot =pTemp;

    if(nTreeLen == 1)//树长为1时,说明已经是最后一个节点

    return ;

    char * pOrgInorder=pInorder;//中序遍历的首地址

    char * pLeftEnd=pInorder;//中序遍历的左子树的最后一个元素的地址

    int nTempLen=0;

    while(*pPreOrder != * pLeftEnd){//前序的首地址值!=中序左子树的最后一个元素地址就一直循环

        if(pPreOrder == NULL || pLeftEnd == NULL)//前序或者左子树的中序最后一个为空时返回

        return ;

        nTempLen++;

        if(nTempLen > nTreeLen)

        break;

        pLeftEnd++;//中序的指针向后移动

    }

    int nLeftLen=0;

    nLeftLen=(int)(pLeftEnd-pOrgInorder);//左子树的长度

    int nRightLen=0;

    nRightLen=nTreeLen-nLeftLen-1;//右子树的长度

    if(nLeftLen>0)//重构左子树

    ReBuild(pPreOrder+1,pInorder,nLeftLen,&((*pRoot)->pLeft));

    if(nRightLen>0)//重构右子树

    ReBuild(pPreOrder+nLeftLen+1,pInorder+nLeftLen+1,nRightLen,&((*pRoot)->pRight));

}

int main()

{

    char szPreOrder[TREELEN]={'a','b','d','c','e','f'};

    char szInorder[TREELEN]={'d','b','a','e','c','f'};

    NODE * pRoot=NULL;

    ReBuild(szPreOrder,szInorder,TREELEN,&pRoot);

    cout << "SUCCESS" << endl;

    return 0;

}

程序中边界检查十分重要,与测试用例的选取相互关联

 

1:  // 3_9重建二叉树.cpp : 定义控制台应用程序的入口点。
   2:  //
   3:   
   4:  #include "stdafx.h"
   5:   
   6:  #include
   7:  #define TREELEN 6
   8:   
   9:  using namespace std;
  10:   
  11:   
  12:   
  13:  struct Node
  14:  {
  15:      Node *pLeft;
  16:      Node *pRight;
  17:      char chValue; 
  18:  };
  19:   
  20:  void ReBuild(char *pPreOrder,
  21:               char *pInOrder,
  22:               int nTreeLen,
  23:               Node **pRoot) //pRoot是一个指向指针的指针 
  24:  {
  25:      if(pPreOrder == NULL || pInOrder == NULL) 
  26:      {    
  27:          return;
  28:      }
  29:   
  30:      //获得前序遍历的第一个节点    
  31:      Node *pTemp = new Node;
  32:      pTemp->chValue = *pPreOrder;   
  33:      pTemp->pLeft = NULL;
  34:      pTemp->pRight = NULL;
  35:   
  36:      //如果根节点为空,把当前节点复制到根节点
  37:      if(*pRoot == NULL) //如果pRoot指向的根节点指针为NULL 
  38:      {
  39:          *pRoot = pTemp; 
  40:      }
  41:   
  42:      //如果当前树长度为1,那么已经是最后一个结点 
  43:      if(nTreeLen == 1)
  44:      {
  45:          return;
  46:      } 
  47:   
  48:      //寻找子树长度
  49:      char* pOrgInOrder = pInOrder;
  50:      char* pLeftEnd = pInOrder;
  51:      int nTempLen = 0;
  52:   
  53:      while(*pPreOrder != *pLeftEnd)
  54:      {
  55:          if(pPreOrder == NULL || pLeftEnd == NULL)
  56:          {
  57:              return;
  58:          }
  59:          nTempLen++;
  60:   
  61:          if(nTempLen > nTreeLen)
  62:          {
  63:              break;
  64:          }
  65:   
  66:          pLeftEnd++;
  67:      }
  68:   
  69:      int nLeftLen = 0;
  70:      nLeftLen = (int)(pLeftEnd - pOrgInOrder);
  71:   
  72:      int nRightLen = 0; 
  73:      nRightLen = nTreeLen - nLeftLen -1;
  74:   
  75:      if(nLeftLen > 0)
  76:      {
  77:          ReBuild(pPreOrder+1, pInOrder, nLeftLen, &((*pRoot)->pLeft));
  78:      }
  79:   
  80:      if(nRightLen > 0)
  81:      {
  82:          ReBuild(pPreOrder + nLeftLen + 1, pInOrder + nLeftLen + 1, nRightLen, &((*pRoot)->pRight));
  83:      }
  84:   
  85:      return;    
  86:  }
  87:   
  88:   
  89:   
  90:  void printInOrder(Node *current)//第一个*解析成Node指针,第二个*把Node指针解析成Node对象 
  91:  {
  92:      if(current != NULL)
  93:      {
  94:          //printInOrder(   &( (*current)->pLeft )   ); //注意这里的 &( (*current)->pLeft ) 
  95:   
  96:          printInOrder(current->pLeft);
  97:          cout<chValue<<" ";
  98:          printInOrder(current->pRight);
  99:          return;
 100:      }
 101:  }
 102:   
 103:  void printPreOrder(Node *current)
 104:  {
 105:   
 106:      if(current!=NULL)
 107:      {
 108:          cout<chValue<<" ";
 109:          printPreOrder(current->pLeft);
 110:          printPreOrder(current->pRight);
 111:          return ;
 112:      }
 113:  }
 114:   
 115:  void printPostOrder(Node *current) 
 116:  {
 117:      if(current != NULL)
 118:      {
 119:          printPostOrder(current->pLeft);
 120:          printPostOrder(current->pRight);
 121:          cout<chValue<<" ";
 122:          return ;
 123:      }
 124:  }
 125:   
 126:  int _tmain(int argc, _TCHAR* argv[])
 127:  {
 128:      //char szPreOrder[TREELEN] = {'z','b','d','c','e','f'}; //非中序遍历结果,结果是错误的
 129:      
 130:      //原:
 131:      //char szPreOrder[TREELEN] = {'a','b','a','e','c','f'};
 132:      //char szInOrder[TREELEN] =   {'d','b','a','e','c','f'}; 
 133:   
 134:      //有重复字符的结点:结果是错误的
 135:      char szPreOrder[TREELEN] = {'a','a','d','e','c','f'};
 136:      char szInOrder[TREELEN] =   {'d','a','a','e','c','f'}; 
 137:   
 138:      Node *pRoot = NULL;
 139:      ReBuild(szPreOrder,szInOrder, TREELEN,&pRoot);
 140:   
 141:      cout<<"前序遍历 :";
 142:      printInOrder(pRoot);
 143:      cout<<endl;< pre="">
 
  
 144:      
 
 
  
 145:      cout<<"中序遍历 :";
 
 
  
 146:      printPreOrder(pRoot);
 
 
  
 147:      cout<<endl;< pre="">
 
  
 148:      
 
 
  
 149:      cout<<"后序遍历 :";
 
 
  
 150:      printPostOrder(pRoot);
 
 
  
 151:      cout<<endl;< pre="">
 
  
 152:   
 
 
  
 153:      system("pause");return 0;
 
 
  
 154:  }
 
 
  
 155: 
</endl;<>
</endl;<>
</endl;<>

 

 

 

栈实现的方式及扩展问题的实现

#include<iostream>

using namespace std;

  

const int Max=20;

struct Node{

    Node *pLeft;

    Node *pRight;

    char chValue;

};

  

template <class T>

class Stack{

public:

    Stack(int s=Max):size(s),top(-1){a=new T[size];}

    ~Stack(){delete[] a;}

    void push(T x)

    {   

        if(top<size-1)

        a[++top]=x;

    }

    T pop()

    {   

        if(top>-1)

        return a[top--];

    }

    T getT() const

    {

        if(top!=-1)

        return a[top];

    }

    bool isEmpty() const{return top==-1;}

    bool isFull() const{return top==(size-1);}

private:

    int size;

    int top;

    T *a;

};

  

void Rebuild(char *pPreOrder,char *pInOrder,int nTreeLen,Node **pRoot)//重建二叉树

{

    if(*pRoot==NULL)

    {

        *pRoot=new Node();

        (*pRoot)->chValue=*pPreOrder;

        (*pRoot)->pLeft=NULL;

        (*pRoot)->pRight=NULL;

    }

  

    if(nTreeLen==1)

        return;

  

    int nLeftLen=0;

    char *InOrder=pInOrder;

    while(*pPreOrder!=*InOrder)

    {

        if(pPreOrder==NULL || InOrder==NULL)

            return;

        nLeftLen++;

        InOrder++;

    }

  

    int nRightLen=nTreeLen-nLeftLen-1;

  

    if(nLeftLen>0)

    {

        Rebuild(pPreOrder+1,pInOrder,nLeftLen,&((*pRoot)->pLeft));

    }

          

    if(nRightLen>0)

    {

        Rebuild(pPreOrder+nLeftLen+1,pInOrder+nLeftLen+1,nRightLen,&((*pRoot)->pRight));

    }

          

}

  

void preOrder1(Node *root)     //递归实现

{

    if(root!=NULL)

        cout<<root->chValue<<endl;

    if(root->pLeft!=NULL)

        preOrder1(root->pLeft);

    if(root->pRight!=NULL)

        preOrder1(root->pRight);

}

  

void preOrder2(Node *root)    //非递归 用栈实现

{

    Stack<Node> stack;

    if(root!=NULL)

        stack.push(*root);

    while(!stack.isEmpty())

    {

        Node *rNode=&stack.pop();;

        cout<<rNode->chValue<<endl;

        if(rNode->pLeft!=NULL)

            preOrder2(rNode->pLeft);

        if(rNode->pRight!=NULL)

            preOrder2(rNode->pRight);

      

    }

  

  

}

  

int main()

{

    char pPreOrder[7]="abdcef";

    char pInOrder[7]="dbaecf";

    int nTreeLen=strlen(pPreOrder);

    Node *pRoot=NULL;

    Rebuild(pPreOrder,pInOrder,nTreeLen,&pRoot);

    preOrder1(pRoot);

    //preOrder2(pRoot);  //非递归实现

    return 0;

}


 

?

/* 

 * 编程之美重建二叉树,扩展问题1,2 

 * 扩展问题1:如果前序和中序的字母可能是相同的,怎么重构出所有可能的解? 

 * 扩展问题2:如何判断给定的前序和中序遍历的结果是合理的? 

 *问题1思路:搜索所有可能的情况,并调用扩展问题2的解决方案,判断此情况是否合理(剪枝操作),如果合法,则构造解

 *问题2思路:递归判断左右子树是否合理,递归的返回条件是到达叶子节点。

 * 

 * */  

    

#include <iostream>   

#include <string>   

using namespace std;  

    

struct Node  

{  

        Node *left;  

        Node *right;  

        char value;  

};  

    

void pre_travel(Node *p)  

{  

        if(p == NULL)  

                return;  

        cout << p->value << endl;  

        pre_travel(p->left);  

        pre_travel(p->right);  

}  

    

    

//枚举所有的情况,递归判断是否合法,如果递归到只剩一个叶子节点   

//则肯定是合法的   

bool isvalid(const char *preorder, const char *inorder, int len)  

{  

        const char *leftend = inorder;  

    

        if(len == 1)  

                return true;  

    

        for(int i=0; i<len; i++, leftend++){  

                if(*leftend == *preorder){  

                        int leftlen = leftend - inorder;  

                        int rightlen = len - leftlen - 1;                 

    

                        bool lres = false, rres = false;  

                        if(leftlen > 0){  

                                lres = isvalid(preorder+1, inorder, leftlen);  

                        }                 

                        if(rightlen > 0){  

                                rres = isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen);  

                        }  

            

                        //如果leftlen和rightlen都大于零,则lres和rres必须都为true,此分割方法才算合法              

                        if((leftlen > 0 && rightlen >0 && lres && rres) ||   

                        (leftlen > 0 && rightlen <=0 && lres) || (left <=0 && rightlen > 0 && rres)){  

                                return true;      

                        }  

                }  

        }  

    

        return false;     

}  

    

    

//枚举法,在枚举的同时使用isvalid函数,排除非法情况   

void rebuild(const char *preorder, const char *inorder, int len, Node **root)  

{  

        if(preorder == NULL || inorder == NULL)  

                return;  

    

        if(*root == NULL){  

                Node *temp = new Node;  

                temp->left = NULL;  

                temp->right = NULL;  

                temp->value = *preorder;  

                *root = temp;  

        }  

    

        if(len == 1)  

                return;  

    

        const char *leftend = inorder;  

    

        for(int i=0; i<len; i++, leftend++){  

                if(*leftend == *preorder){  

                        int leftlen = leftend - inorder;  

                        int rightlen = len - leftlen - 1;  

    

                        if(leftlen > 0  && rightlen >0){  

                                if(isvalid(preorder+1, inorder, leftlen) && isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen)){  

                                        rebuild(preorder+1, inorder, leftlen, &((*root)->left));  

                                        rebuild(preorder+leftlen+1, inorder+leftlen+1, rightlen, &((*root)->right));  

                                }  

                        }else if(leftlen > 0 && rightlen <= 0){  

                                if(isvalid(preorder+1, inorder, leftlen))  

                                        rebuild(preorder+1, inorder, leftlen, &((*root)->left));  

                        }else if(leftlen <=0 && rightlen >0){  

                                if(isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen))  

                                        rebuild(preorder+leftlen+1, inorder+leftlen+1, rightlen, &((*root)->right));  

                        }  

                            

                }  

        }  

}  

    

int main()  

{  

        string pre1 = "abdefc";  

        string mid1 = "dbfeac";  

    

        string pre2 = "abdefc";  

        string mid2 = "dcfeab";  

    

        //有重复的字母   

        string pre3 = "aadcef";  

        string mid3 = "daaecf";  

    

        bool valid = isvalid(pre1.c_str(), mid1.c_str(), pre1.length());  

        cout << valid << endl;  

    

        valid = isvalid(pre2.c_str(), mid2.c_str(), pre2.length());  

        cout << valid << endl;  

            

        valid = isvalid(pre3.c_str(), mid3.c_str(), pre3.length());  

        cout << valid << endl;  

           

        Node *root = NULL;  

        rebuild(pre3.c_str(), mid3.c_str(), 6, &root);  

        pre_travel(root);  

     

        return 0;  

}

posted @ 2013-06-25 16:58  夜雨阑珊  阅读(485)  评论(0编辑  收藏  举报