二叉树先序遍历结果为aferpkwhjl
, 中序遍历结果为repfwkajhl
,那么后序遍历结果是什么呢?
先序遍历的顺序是:根 -左子树 -右子树
中序遍历的顺序是:左子树 -根 -右子树
后序遍历的顺序是:左子树 -右子树 -根
由此可以得到一个结论:先序遍历的第一个元素一定是树的根,中序遍历根的左侧一定是左子树的遍历结果, 右侧一定是
右子树遍历的结果
那么这道题的解决思路是:1.根据先序遍历的结果可以得到当前树的根
2. 根据中序遍历的结果和前面得到的根, 可以得到左子树的中序遍历结果和右子树的中序遍历
果
3.根据左子树中序遍历结果可以在当前树的先序遍历结果中得到左子树的先序遍历结果
(左子树中元素的顺序要与当前树先序遍历结果中元素的顺序一致),右子树也是如此
4.将左子树和右子树分别设置为当前树。重复进行1-3步骤(这是树的福利, 逻辑很简单,
使用递归后,代码就简单多了)
我们可以采用单向链表来存储树的先序,中序遍历结果;
link.h
#ifndef LINK
#define LINK
#define SUCCESS 10000
#define FAILURE 10001
typedef char ElemType;
typedef struct node //链表的节点
{
ElemType data;
struct node * next;
}Node, *pNode;
int Init(pNode *); //初始化链表(建立头节点)
int Insert(pNode, ElemType);//尾插法
int Delete(pNode, ElemType);//根据节点的数据,来删除对应的节点
pNode Find(pNode, ElemType);//根据节点的数据,来找到对应节点的前一个节点的指针(得到前一个节点的指针,是为了方便在单向链表中删除该节点)
int GetLength(pNode);//得到链表中节点的个数,本次程序并未用到该接口, 可以不用理他
int Destroy(pNode * phead);//销毁一个链表,即删除所有的节点(包括头节点),本次程序中新生左子树链表直接继承当前树链表,所以不需要该接口来销毁一个链表,只需要将当前树的根节点free掉即可
pNode CreateLink(ElemType e[], int length);//根据树的先序,中序遍历结果,建立相对应的链表,本次程序中只在main中建立初始树的先序,中序遍历链表, 后面子树遍历链表并未用到该接口
#endif
link.c
#include <stdio.h>
#include <stdlib.h>
#include "link.h"
int Init(pNode *phead)
{
if (phead == NULL)
return FAILURE;
(*phead) = (pNode)malloc(sizeof(Node) * 1);
if (*phead == NULL)
return FAILURE;
(*phead)->next = NULL;
return SUCCESS;
}
int Insert(pNode head, ElemType e)
{
if (head == NULL)
return FAILURE;
pNode p = head;
while(p->next != NULL)
p = p->next;
pNode newnode = (pNode)malloc(sizeof(Node) * 1);
if (newnode == NULL)
return FAILURE;
newnode->data = e;
newnode->next = NULL;
p->next = newnode;
return SUCCESS;
}
int Delete(pNode head, ElemType e)
{
pNode ret = Find(head, e);
if (ret == NULL)
return FAILURE;
pNode p = ret->next;
ret->next = p->next;
free(p);
return SUCCESS;
}
pNode Find(pNode head, ElemType e)
{
if (head == NULL || head->next == NULL)
return NULL;
pNode p = head;
while (p->next != NULL && p->next->data != e)
p = p->next;
if (p->next == NULL)
return NULL;
return p;
}
/*
int GetLength(pNode head)
{
if (head == NULL)
return FAILURE;
int count = 0;
pNode p = head;
while (p->next != NULL)
{
count++;
p = p->next;
}
return count;
}
int Destroy(pNode * phead)
{
if (phead == NULL || *phead == NULL)
return FAILURE;
pNode p = *phead, pp;
while (p != NULL)
{
pp = p->next;
free(p);
p = pp;
}
phead = NULL;
return SUCCESS;
}
*/
pNode CreateLink(ElemType e[], int length)
{
pNode head;
int ret = Init(&head);
if (ret == FAILURE || e == NULL)
return NULL;
for (ret = 0; ret < length; ret++)
{
Insert(head, e[ret]);
}
return head;
}
tree.h
#ifndef TREE
#define TREE
#include "link.h"
void InOrder_Left_Right(ElemType rootdata, pNode In, pNode * LeftIn, pNode * RightIn);
void PreOrder_Left_Right(pNode Pre, pNode In, pNode * LeftPre, pNode * RightPre, pNode * LeftIn, pNode * RightIn);
void Post(pNode Pre, pNode In);
#endif
tree.c
#include "link.h"
#include "tree.h"
void InOrder_Left_Right(ElemType rootdata, pNode In, pNode * LeftIn, pNode * RightIn)
{
if (LeftIn == NULL || Init(RightIn) != SUCCESS || In == NULL)
return;
pNode ret;
*LeftIn = In; //左子树中序链表直接继承当前树中序链表,就可以省去销毁当前树链表的步骤
if (Init(RightIn) == FAILURE)
return;
ret = Find(In, rootdata);
if (ret == NULL)
return;
else
{
(*RightIn)->next = ret->next->next;//本质是建立右子树中序遍历链表
free(ret->next);//删除当前树的根节点
ret->next = NULL;//本质是建立左子树中序遍历链表
}
}
void PreOrder_Left_Right(pNode Pre, pNode In, pNode * LeftPre, pNode * RightPre, pNode * LeftIn, pNode * RightIn)
{
if (LeftPre == NULL || Init(RightPre) != SUCCESS || Pre == NULL || In == NULL || Pre->next == NULL || In->next == NULL)
return ;
ElemType rootdata = Pre->next->data, e;
pNode p, ret;
InOrder_Left_Right(rootdata, In, LeftIn, RightIn);
(*LeftPre) = Pre;//左子树先序链表直接继承当前树先序遍历链表
Delete(*LeftPre, rootdata);//删除根节点
p = Pre->next;
while (p != NULL)
{
ret = Find(*LeftIn, p->data);
e = p->data;
p = p->next;
if (ret == NULL)
{
Insert(*RightPre, e);//本质是建立右子树先序遍历链表
Delete(*LeftPre, e);//本质是建立左子树先序遍历链表
}
}
}
void Post(pNode Pre, pNode In)
{
if (Pre->next == NULL || In->next == NULL || Pre == NULL || In == NULL)
return;
ElemType e = Pre->next->data;//先保存根节点数据,后面Pre链表会被修改,所以一定要先保存一下
pNode LeftPre, LeftIn, RightPre, RightIn;//建立左子树,右子树先序,中序遍历链表
PreOrder_Left_Right(Pre, In, &LeftPre, &RightPre, &LeftIn, &RightIn);
Post(LeftPre, LeftIn);//先左子树
Post(RightPre, RightIn);//然后右子树
printf("%c",e);//最后根节点
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tree.h"
#include "link.h"
int main()
{
ElemType pre[20] = "aferpkwhjl";
ElemType in[20] = "repfwkajhl";
pNode Pre = CreateLink(pre, strlen(pre));
pNode In = CreateLink(in, strlen(in));
Post(Pre, In);
printf("\n");
return 0;
}
~
结果为:rpewkfjlha