#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; }