zoukankan      html  css  js  c++  java
  • 重建二叉树

    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;  

    }

  • 相关阅读:
    海康威视DS-A80648S管理系统配置
    海康威视iVMS-8700平台录像计划——配置CVR存储
    架构师成长之路5.7-Saltstack数据系统
    架构师成长之路5.6-Saltstack配置管理(jinja模板)
    架构师成长之路5.5-Saltstack配置管理(状态间关系)
    架构师成长之路5.4-Saltstack配置管理(LAMP架构案例)
    架构师成长之路5.3-Saltstack配置管理(State状态模块)
    架构师成长之路5.2-Saltstack远程执行
    架构师成长之路5.1-Saltstack安装及入门
    16 Zabbix4.4.1系统告警“Zabbix agent is not available (for 3m)“
  • 原文地址:https://www.cnblogs.com/fickleness/p/3155035.html
Copyright © 2011-2022 走看看