重建二叉树
2013-06-25 16:58
225 查看
/article/5115836.html
中序和后序也能重构------------
前序和后序好像不能重构----没找到资料
已只二叉树的前序和中序遍历,要求构建出完整的二叉树
如前序遍历为:abdcef
中序遍历为:dbaecf
由于前序遍历先访问的是根节点所以整棵树的根节点是a
中序遍历中,先访问左子树,再访问右子树,所以db是左子树,ecf是右子树
如此递归下去,可以找到整棵树的结构
#include<iostream>
#defineTREELEN6
usingnamespacestd;
structNODE{
NODE*pLeft;
NODE*pRight;
charchValue;
};
voidReBuild(char*pPreOrder,char*pInorder,intnTreeLen,NODE**pRoot){
if(pPreOrder==NULL||pInorder==NULL)//两个数组不为空
return;
NODE*pTemp=newNODE;
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;//中序遍历的左子树的最后一个元素的地址
intnTempLen=0;
while(*pPreOrder!=*pLeftEnd){//前序的首地址值!=中序左子树的最后一个元素地址就一直循环
if(pPreOrder==NULL||pLeftEnd==NULL)//前序或者左子树的中序最后一个为空时返回
return;
nTempLen++;
if(nTempLen>nTreeLen)
break;
pLeftEnd++;//中序的指针向后移动
}
intnLeftLen=0;
nLeftLen=(int)(pLeftEnd-pOrgInorder);//左子树的长度
intnRightLen=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));
}
intmain()
{
charszPreOrder[TREELEN]={'a','b','d','c','e','f'};
charszInorder[TREELEN]={'d','b','a','e','c','f'};
NODE*pRoot=NULL;
ReBuild(szPreOrder,szInorder,TREELEN,&pRoot);
cout<<"SUCCESS"<<endl;
return0;
}
程序中边界检查十分重要,与测试用例的选取相互关联
栈实现的方式及扩展问题的实现
?
中序和后序也能重构------------
前序和后序好像不能重构----没找到资料
已只二叉树的前序和中序遍历,要求构建出完整的二叉树
如前序遍历为:abdcef
中序遍历为:dbaecf
由于前序遍历先访问的是根节点所以整棵树的根节点是a
中序遍历中,先访问左子树,再访问右子树,所以db是左子树,ecf是右子树
如此递归下去,可以找到整棵树的结构
#include<iostream>
#defineTREELEN6
usingnamespacestd;
structNODE{
NODE*pLeft;
NODE*pRight;
charchValue;
};
voidReBuild(char*pPreOrder,char*pInorder,intnTreeLen,NODE**pRoot){
if(pPreOrder==NULL||pInorder==NULL)//两个数组不为空
return;
NODE*pTemp=newNODE;
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;//中序遍历的左子树的最后一个元素的地址
intnTempLen=0;
while(*pPreOrder!=*pLeftEnd){//前序的首地址值!=中序左子树的最后一个元素地址就一直循环
if(pPreOrder==NULL||pLeftEnd==NULL)//前序或者左子树的中序最后一个为空时返回
return;
nTempLen++;
if(nTempLen>nTreeLen)
break;
pLeftEnd++;//中序的指针向后移动
}
intnLeftLen=0;
nLeftLen=(int)(pLeftEnd-pOrgInorder);//左子树的长度
intnRightLen=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));
}
intmain()
{
charszPreOrder[TREELEN]={'a','b','d','c','e','f'};
charszInorder[TREELEN]={'d','b','a','e','c','f'};
NODE*pRoot=NULL;
ReBuild(szPreOrder,szInorder,TREELEN,&pRoot);
cout<<"SUCCESS"<<endl;
return0;
}
程序中边界检查十分重要,与测试用例的选取相互关联
1://3_9重建二叉树.cpp:定义控制台应用程序的入口点。
2://
3:
4:#include"stdafx.h"
5:
6:#include
7:#defineTREELEN6
8:
9:usingnamespacestd;
10:
11:
12:
13:structNode
14:{
15:Node*pLeft;
16:Node*pRight;
17:charchValue;
18:};
19:
20:voidReBuild(char*pPreOrder,
21:char*pInOrder,
22:intnTreeLen,
23:Node**pRoot)//pRoot是一个指向指针的指针
24:{
25:if(pPreOrder==NULL||pInOrder==NULL)
26:{
27:return;
28:}
29:
30://获得前序遍历的第一个节点
31:Node*pTemp=newNode;
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:intnTempLen=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:intnLeftLen=0;
70:nLeftLen=(int)(pLeftEnd-pOrgInOrder);
71:
72:intnRightLen=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:voidprintInOrder(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:voidprintPreOrder(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:voidprintPostOrder(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(intargc,_TCHAR*argv[])
127:{
128://charszPreOrder[TREELEN]={'z','b','d','c','e','f'};//非中序遍历结果,结果是错误的
129:
130://原:
131://charszPreOrder[TREELEN]={'a','b','a','e','c','f'};
132://charszInOrder[TREELEN]={'d','b','a','e','c','f'};
133:
134://有重复字符的结点:结果是错误的
135:charszPreOrder[TREELEN]={'a','a','d','e','c','f'};
136:charszInOrder[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");return0;
154:}
155:
</endl;<>
</endl;<>
</endl;<>
栈实现的方式及扩展问题的实现
#include<iostream> usingnamespacestd; constintMax=20; structNode{ Node*pLeft; Node*pRight; charchValue; }; template<classT> classStack{ public: Stack(ints=Max):size(s),top(-1){a=newT[size];} ~Stack(){delete[]a;} voidpush(Tx) { if(top<size-1) a[++top]=x; } Tpop() { if(top>-1) returna[top--]; } TgetT()const { if(top!=-1) returna[top]; } boolisEmpty()const{returntop==-1;} boolisFull()const{returntop==(size-1);} private: intsize; inttop; T*a; }; voidRebuild(char*pPreOrder,char*pInOrder,intnTreeLen,Node**pRoot)//重建二叉树 { if(*pRoot==NULL) { *pRoot=newNode(); (*pRoot)->chValue=*pPreOrder; (*pRoot)->pLeft=NULL; (*pRoot)->pRight=NULL; } if(nTreeLen==1) return; intnLeftLen=0; char*InOrder=pInOrder; while(*pPreOrder!=*InOrder) { if(pPreOrder==NULL||InOrder==NULL) return; nLeftLen++; InOrder++; } intnRightLen=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)); } } voidpreOrder1(Node*root)//递归实现 { if(root!=NULL) cout<<root->chValue<<endl; if(root->pLeft!=NULL) preOrder1(root->pLeft); if(root->pRight!=NULL) preOrder1(root->pRight); } voidpreOrder2(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); } } intmain() { charpPreOrder[7]="abdcef"; charpInOrder[7]="dbaecf"; intnTreeLen=strlen(pPreOrder); Node*pRoot=NULL; Rebuild(pPreOrder,pInOrder,nTreeLen,&pRoot); preOrder1(pRoot); //preOrder2(pRoot);//非递归实现 return0; } |
/* *编程之美重建二叉树,扩展问题1,2 *扩展问题1:如果前序和中序的字母可能是相同的,怎么重构出所有可能的解? *扩展问题2:如何判断给定的前序和中序遍历的结果是合理的? *问题1思路:搜索所有可能的情况,并调用扩展问题2的解决方案,判断此情况是否合理(剪枝操作),如果合法,则构造解 *问题2思路:递归判断左右子树是否合理,递归的返回条件是到达叶子节点。 * **/ #include<iostream> #include<string> usingnamespacestd; structNode { Node*left; Node*right; charvalue; }; voidpre_travel(Node*p) { if(p==NULL) return; cout<<p->value<<endl; pre_travel(p->left); pre_travel(p->right); } //枚举所有的情况,递归判断是否合法,如果递归到只剩一个叶子节点 //则肯定是合法的 boolisvalid(constchar*preorder,constchar*inorder,intlen) { constchar*leftend=inorder; if(len==1) returntrue; for(inti=0;i<len;i++,leftend++){ if(*leftend==*preorder){ intleftlen=leftend-inorder; intrightlen=len-leftlen-1; boollres=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)){ returntrue; } } } returnfalse; } //枚举法,在枚举的同时使用isvalid函数,排除非法情况 voidrebuild(constchar*preorder,constchar*inorder,intlen,Node**root) { if(preorder==NULL||inorder==NULL) return; if(*root==NULL){ Node*temp=newNode; temp->left=NULL; temp->right=NULL; temp->value=*preorder; *root=temp; } if(len==1) return; constchar*leftend=inorder; for(inti=0;i<len;i++,leftend++){ if(*leftend==*preorder){ intleftlen=leftend-inorder; intrightlen=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)); } }elseif(leftlen>0&&rightlen<=0){ if(isvalid(preorder+1,inorder,leftlen)) rebuild(preorder+1,inorder,leftlen,&((*root)->left)); }elseif(leftlen<=0&&rightlen>0){ if(isvalid(preorder+leftlen+1,inorder+leftlen+1,rightlen)) rebuild(preorder+leftlen+1,inorder+leftlen+1,rightlen,&((*root)->right)); } } } } intmain() { stringpre1="abdefc"; stringmid1="dbfeac"; stringpre2="abdefc"; stringmid2="dcfeab"; //有重复的字母 stringpre3="aadcef"; stringmid3="daaecf"; boolvalid=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); return0; } |
相关文章推荐
- 重建二叉树
- QUDOJ-78 重建二叉树 (中序后续推前序)
- 重建二叉树
- 算法竞赛入门经典(第2版)习题6-3 二叉树重建 UVa536
- 第9天 重建二叉树
- 二叉树之重建
- 重建二叉树
- 剑指offer面试题6——重建二叉树(递归)
- [牛客网,剑指offer,python] 重建二叉树
- 【剑指**】7.重建二叉树
- 【编程题】根据前序中序重建二叉树
- 根据给定先序和中序序列来重建二叉树
- 3.9重建二叉树
- 第3章 结构之法——重建二叉树
- 重建二叉树
- 【剑指Offer面试题】 九度OJ1385:重建二叉树
- 重建二叉树
- 根据二叉树的先序、中序遍历结果重建二叉树
- 【剑指Offer】面试题6:重建二叉树
- 根据前序遍历和中序遍历重建二叉树