#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; } |
作者:像少年啦飞驰
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步