阅读需知:
1.至少需要了解前、中、后三种遍历,函数递归与堆栈;
2.下文中的“根”结点指树的根结点与“子根结点”(作者自己的叫法),“子根节点”指各种子树的根结点,可以简单理解为除了根节点外的所有结点。
在前、中、后三个遍历次序中,我们可以发现始终是左孩子比右孩子先出,左子树比右子树先出,
而区别则在于“根”节点输出位置不同。
(1)中序遍历的一个好处是让我们明晰了左右子树各自的结点数目。
(2)而前后遍历在“根”节点的输出上完全相反,除非遇见了叶结点。
根据(1)我们可以知道各个子树的结点数目,即各个子区间范围
根据(2)我们可以取各个子区间的最后一位存储进新数组,从而实现后序变先序。
代码如下所示:
(数组均采用了动态数组,亦可改用为足够大的数组;getchar()是为了吃缓存,即吃enter)
#include<stdio.h>
#include<stdlib.h>
struct Stack {
int ra, la,rb,rl;
Stack* pre_QJ;
};
struct Stack* front=NULL;
char* a, * b,*c,*s;
int i;
void funcation1(int ra,int la,int rb,int lb);
void funcation2(int ra, int la, int rb, int lb);
Stack* push(Stack* new_node);
Stack* pop(void);
int isempty();
//主函数
int main() {
int n;
printf("请输入树的结点个数:");
scanf("%d",&n);
printf("请输入树的中序遍历结果:");
a = (char *)malloc(sizeof(char) * n);
getchar();
for (i = 0; i < n; i++) {
scanf("%c", &a[i]);
}
printf("请输入树的后序遍历结果:");
b = (char*)malloc(sizeof(char)*n);
getchar();
for (i = 0; i < n;i++) {
scanf("%c",&b[i]);
}
i = 0;
c = (char*)malloc(sizeof(char) * n);
funcation1(0,n-1,0,n-1);
printf("其先序遍历的结果为(递归):");
for (i = 0; i < n; i++) {
printf("%c",c[i]);
}
printf("\n");
i = 0;
s = (char*)malloc(sizeof(char) * n);
printf("其先序遍历的结果为(非递归):");
funcation2(0, n - 1, 0, n - 1);
for (i = 0; i < n; i++) {
printf("%c", s[i]);
}
return 0;
}
//递归版
void funcation1(int ra, int la, int rb, int lb){
if (lb < rb||la<ra)return;//退出递归条件,记为A
c[i++] = b[lb];
int m = ra;
while (a[m] != b[lb]) {
if (m < la)m++;
else break;
}
int d = la - m;
funcation1(ra,m-1,rb,lb-d-1);
funcation1(m + 1, la, lb - d, lb - 1);
}
//非递归版,写出递归版我们发现需要堆栈存储两个数组的区间
void funcation2(int ra, int la, int rb, int lb) {
int m;
while (1) {
while (ra<=la&&rb<=lb) {//进行条件是递归版退出递归条件的反逻辑值,即为!A
s[i++] = b[lb];//后序遍历根后出,先序遍历根先出...故此将后序遍历尾值置于首位
m = ra;
while (m < la && a[m] != b[lb]) {
m++;
}//在中序遍历中寻找根值所在位置,为接下来分割区间做准备
Stack* new_node;
new_node = (Stack*)malloc(sizeof(Stack));
//创建新记录条目。
int d = la - m;//表示右子树的节点数目
new_node->ra = m + 1; new_node->la = la;
new_node->rb = lb - d; new_node->rl = lb - 1;
//记录右子树在中序与后序数组的对应区间;
front = push(new_node);//将新记录条目存入堆栈
ra = ra; la = m - 1; rb = rb; lb = lb - d - 1;//设置处理左子树相应区间
}
if (!isempty()) {//堆栈不空则重置两个数组所需查找区间范围,并抛出栈堆值
ra = front->ra;
rb = front->rb;
la = front->la;
lb = front->rl;
pop();
}
else break;//为空则退出内层循环
}
return;//退出外层循环
}
Stack* push(Stack* new_node) {
new_node->pre_QJ = front;
front = new_node;
return front;
}
Stack* pop(void) {
Stack* temp;
if (!isempty()) {
temp = front;
front = front->pre_QJ;
free(temp);
}
return front;
}
int isempty() {
if (front == NULL)return 1;
else return 0;
}