zz http://blog.csdn.net/vividonly/article/details/6688327
编程之美3.9:重建二叉树
扩展问题1:如果前序和中序遍历的字母有重复的,那么怎么构造所有可能的解呢?
扩展问题2:如何判断给定的前序遍历和中序遍历的结果是合理的?
思路:
问题1:搜索所有可能的情况,并调用扩展问题2的解决方案,判断此情况是否合理(剪枝操作),如果合法,则构造解
问题2:递归判断左右子树是否合理,递归的返回条件是到达叶子节点。
代码及测试情况如下:
1 /* 2 * 编程之美重建二叉树,扩展问题1,2 3 * 扩展问题1:如果前序和中序的字母可能是相同的,怎么重构出所有可能的解? 4 * 扩展问题2:如何判断给定的前序和中序遍历的结果是合理的? 5 * 6 * */ 7 8 #include <iostream> 9 #include <string> 10 using namespace std; 11 12 struct Node 13 { 14 Node *left; 15 Node *right; 16 char value; 17 }; 18 19 void pre_travel(Node *p) 20 { 21 if(p == NULL) 22 return; 23 cout << p->value << endl; 24 pre_travel(p->left); 25 pre_travel(p->right); 26 } 27 28 29 //枚举所有的情况,递归判断是否合法,如果递归到只剩一个叶子节点 30 //则肯定是合法的 31 bool isvalid(const char *preorder, const char *inorder, int len) 32 { 33 const char *leftend = inorder; 34 35 if(len == 1) 36 return true; 37 38 for(int i=0; i<len; i++, leftend++){ 39 if(*leftend == *preorder){ 40 int leftlen = leftend - inorder; 41 int rightlen = len - leftlen - 1; 42 43 bool lres = false, rres = false; 44 if(leftlen > 0){ 45 lres = isvalid(preorder+1, inorder, leftlen); 46 } 47 if(rightlen > 0){ 48 rres = isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen); 49 } 50 51 //如果leftlen和rightlen都大于零,则lres和rres必须都为true,此分割方法才算合法 52 if((leftlen > 0 && rightlen >0 && lres && rres) || 53 (leftlen > 0 && rightlen <=0 && lres) || (left <=0 && rightlen > 0 && rres)){ 54 return true; 55 } 56 } 57 } 58 59 return false; 60 } 61 62 63 //枚举法,在枚举的同时使用isvalid函数,排除非法情况 64 void rebuild(const char *preorder, const char *inorder, int len, Node **root) 65 { 66 if(preorder == NULL || inorder == NULL) 67 return; 68 69 if(*root == NULL){ 70 Node *temp = new Node; 71 temp->left = NULL; 72 temp->right = NULL; 73 temp->value = *preorder; 74 *root = temp; 75 } 76 77 if(len == 1) 78 return; 79 80 const char *leftend = inorder; 81 82 for(int i=0; i<len; i++, leftend++){ 83 if(*leftend == *preorder){ 84 int leftlen = leftend - inorder; 85 int rightlen = len - leftlen - 1; 86 87 if(leftlen > 0 && rightlen >0){ 88 if(isvalid(preorder+1, inorder, leftlen) && isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen)){ 89 rebuild(preorder+1, inorder, leftlen, &((*root)->left)); 90 rebuild(preorder+leftlen+1, inorder+leftlen+1, rightlen, &((*root)->right)); 91 } 92 }else if(leftlen > 0 && rightlen <= 0){ 93 if(isvalid(preorder+1, inorder, leftlen)) 94 rebuild(preorder+1, inorder, leftlen, &((*root)->left)); 95 }else if(leftlen <=0 && rightlen >0){ 96 if(isvalid(preorder+leftlen+1, inorder+leftlen+1, rightlen)) 97 rebuild(preorder+leftlen+1, inorder+leftlen+1, rightlen, &((*root)->right)); 98 } 99 100 } 101 } 102 } 103 104 int main() 105 { 106 string pre1 = "abdefc"; 107 string mid1 = "dbfeac"; 108 109 string pre2 = "abdefc"; 110 string mid2 = "dcfeab"; 111 112 //有重复的字母 113 string pre3 = "aadcef"; 114 string mid3 = "daaecf"; 115 116 bool valid = isvalid(pre1.c_str(), mid1.c_str(), pre1.length()); 117 cout << valid << endl; 118 119 valid = isvalid(pre2.c_str(), mid2.c_str(), pre2.length()); 120 cout << valid << endl; 121 122 valid = isvalid(pre3.c_str(), mid3.c_str(), pre3.length()); 123 cout << valid << endl; 124 125 Node *root = NULL; 126 rebuild(pre3.c_str(), mid3.c_str(), 6, &root); 127 pre_travel(root); 128 129 return 0; 130 }