这题我又做了好久,真是菜。这题我觉得关键是明白为什么要用先序中序后序的首位进行相关运算。比如我一开始找规律,是想用一个begin,一个end,来标识出两棵需要递归求解的树。而这里的
begin对应的是前序遍历的开头的数组,而end则对应的是后序遍历的末尾。然后这样牛头不对马嘴的乱找规律于是就出bug了。后来也是在网上看到了别人的解法,又听了cy姥姥的课,懂得怎么写出来,但是对于为什么这题采用三个参数进行递归求解依然一知半解,个人的理解是:
1、采用这三个参数依然可以进行很清楚的递归求解,如果只用两个,就很难分的清先序后序谁对应谁
2、进行找规律进行递归也要有基本法,不是第一次行了就行,要接下来的每一次都可以,要具有普适性。
代码如下,但是真的,每个人写出来基本都是这样,关键是能否理解其中的算法的含义。我记得有个老哥画的图还蛮清楚,但是毕竟一个个人博客,估计也没多少人看。我也就是自己教自己,所以也不多写啦。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct StackTree Tree;
struct StackTree
{
int data;
Tree* next;
};
/*
* 这道题的思路我是这样想的,一个是创栈;
* 创建栈的过程中得到前序,而后每次Pop,得到中序遍历;
* 最后通过递归遍历树得到后序。
* 我觉得这题无论是链栈或者是数组创建栈都是可以的
*/
Tree* CreateStack();
int Pop(Tree* T);/* 让栈返回一个整型元素 */
void Push(Tree* T,int data);/*往栈内压入元素 */
void Input(int* preorder,int* inorder,Tree* T,int num);
int isEmpty(Tree* T);
void Postorder(int* preorder,int* inorder,int* postorder,int num,int pre_L,int post_L,int in_L);
int main(void)
{
int *preorder,*inorder,*postorder,num;
Tree* T;
T = CreateStack();
scanf("%d",&num);
preorder=(int*)malloc(sizeof(int)*num);
inorder=(int*)malloc(sizeof(int)*num);
postorder=(int*)malloc(sizeof(int)*num);
/* 通过栈获取中序和前序 */
Input(preorder,inorder,T,num);
Postorder(preorder,inorder,postorder,num,0,0,0);
for(int i = 0;i < num-1;i++)
printf("%d ",postorder[i]);
printf("%d",postorder[num-1]);
return 0;
}
void Input(int* preorder,int* inorder,Tree* T,int num)
{
int data;
int j=0,k=0;
for(int i = 0;i < 2*num;i++)
{
char s[5];
scanf("%s",s);
if(strcmp(s,"Push") == 0){
/* 数据入栈,并且创建前序数组 */
scanf("%d",&data);
preorder[j++] = data;
Push(T,data);
}
else if(strcmp(s,"Pop") == 0){
/* 数据出栈,并且创建中序数组 */
if(!isEmpty(T))
inorder[k++] = Pop(T);
}
}
}
void Postorder(int* preorder,int* inorder,int* postorder,int num,int pre_L,int post_L,int in_L)
{
int L,R,i;
if(num == 0) return;
if(num == 1){
postorder[post_L] = preorder[pre_L];
return;
}
postorder[post_L+num-1] = preorder[pre_L];
/* 找到根节点 */
for(i = 0;i <num;i++)
if(preorder[pre_L] == inorder[i+in_L]) break;
L = i; /* 左子树节点数量 */
R = num - L - 1;/* 右子树节点数量 */
/* 这里的pre_L+1,意味着先序后移一位,前面的根节点已经排好了,左子树的中序首位、后序首位依然如旧。*/
Postorder(preorder,inorder,postorder,L,pre_L+1,post_L,in_L);
/* 这里的pre_L+L+1,意味着右子树的先序首位是在左子树遍历完再加上一个根节点后的元素,
* 中序因为没有被排根节点,所以中序只是+L,后序因为末尾变动,所以要+L+1;
*/
Postorder(preorder,inorder,postorder,R,pre_L+1+L,post_L+L,in_L+L+1);
return;
}
Tree* CreateStack()
{
Tree* p;
p = (Tree*)malloc(sizeof(Tree));
if(p)
p->next = NULL;
return p;
}
void Push(Tree* T,int data)
{
Tree* p;
p = (Tree*)malloc(sizeof(Tree));
p->data = data;
p->next = T->next;
T->next = p;
}
int Pop(Tree* T)
{
Tree* p;
int tmp;
p = T->next;
tmp = p->data;
T->next = T->next->next;
free(p);
return tmp;
}
int isEmpty(Tree* T){
return T->next == NULL;
}
最后一句话,与君共勉:我与我周旋久,宁做我。