重建二叉树
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; } |