1.首先先说一个想法,也是学校的题,如果二叉树通过前序和中序遍历来生成后序遍历,我们是不是可以通过前中序来输出一个树,然后将树给还原成完整的树,最后再后序遍历这颗树,不就OK了
char preA[]={'A','B','D','E','G','C','H','F'};前序
char inA[]={'D','B','E','G','A','H','C','F'};中序
这是测试用例
typedef struct TreeNode{ char data; struct TreeNode*left; struct TreeNode*right; }BtNode; BtNode * creatTreenode(char x){ BtNode*node=(BtNode*)malloc(sizeof(BtNode)); node->data=x; node->left=node->right=NULL; return node; }
上面的是基本内容
下面的才是构建二叉树
BtNode *creatBItree(int len,char *preA,char *inA){ int i; if(len==0){ return NULL; } BtNode* root=creatTreenode(preA[0]); for(i=0;i<len;i++){ if(inA[i]==root->data) break; } root->left=creatBItree(i, preA+1, inA); root->right=creatBItree(len-i-1, preA+i+1, inA+i+1); return root;}
1.preA,inA在最开始是先序遍历和中序遍历,然而核心思想就是找他们的交点,不同的交点就是不同的根,从而分割开左右树 第一个交点是A 。i,len(B未找到之前)此时都等于4进入A的左树构建
2.preA+1: [B,D,E,G,C,H,F]从B开始,来寻找B的左树,len和i(D未找到之前)此时等于1,当我找到了B也就是相当于B来视作为根,构建B的左树
3.preA+1: [D,E,G,C,H,F],此时找到了D,因为D是中序的开头,找到D len等于0那么也就是说D的左树为空,那么来看他的右树,(D的左树和右树是都是在D的那一层的),所以右树的1-1=0,D的右节点也是空
4.退到B的地方,B所要找的D和E是在一个面上的,也就是说都退到B的地方,此时i变了,但是len 没变,len依旧是4,但是已经找到B了所以i是1,那么B-i-1,
5.进入B的右节点E的时候,B-i-1为2,也就是说B的右节点有两个 ,preA+1+i是从B的那一层开始(len=4 ,i=1,B被找到)所以从B,D,E,G,C,H,F 开始 +,之后是preA+1+i到了E,in A+i+1 也是从E开始E,G,A,H,C,F
此时写到第四条突然恍然大悟,
i的含义是找到的根节点左子树的节点。
len-i-1的含义其实是当我已经找到根A的时候,我又去找了下一个根B此时A B之间隔着的也就是B的右节点有几个。
遍历左子树的范围是A此时为根节点,先序范围是preA+1~preA+i-1(preA+i-1的含义其实根据那个中序能知道,都加上i那么中序的A左边全是左树,也就是inA+i-1),中序遍历范围是inA~inA+i-1 (这部分属于根节点的左子树)
遍历右子树(他的开始是找到A的右边也就是中序遍历inA+i+1,到inA+length-1,先序遍历的preA+i+1,到preA+length-1)
inA+i是我们要找的根,这时候一左一右,左边为左子树的边界点,右边为右子树的边界点。
构建左子树时候PreA+1就是为了先序遍历的++,
所以这么一步一步分析自然核心思路就会出来,我会以后争取多去写题,做一些更有意义的事情