#include <stdio.h>
#include <stdlib.h>
/*
* 给出RNL,RLN,NRL是为了,有更多解决问题的方法
*/
typedef struct node
{
char data;
struct node *lchild,*rchild;
}*BitTree,BitNode;
//创建二叉树
void CreateBitTree(BitTree &tree)
{
//先序创建二叉树
char ch;
if ((ch=getchar())=='#')
tree=NULL;
else
{
//先序创建二叉树,NLR
tree=(BitNode*)malloc(sizeof(BitNode));
tree->data=ch;
CreateBitTree(tree->lchild);
CreateBitTree(tree->rchild);
}
}
//先序递归遍历二叉树 NLR
/*
* 所谓的先序遍历 NLR
* 就是把每个结点都当成当前结点子树的跟结点,
* 思想:
* 1.先判断是跟?是,接着判断左子树是跟?是接着递归判断左子树是跟?不是结束递归指针指向父节点,
* 2.判断右子树是否是跟?是,判断左子树是跟?重复1
*/
void PreOrder(BitTree tree)
{
if (tree) //NLR
{
printf("%c ",tree->data); // 1. 结点存在,是根节点,打印
PreOrder(tree->lchild);
//2.判断左子树是不是下一个节点的根节点,如果存在,就是下一个子树的根节点,递归到1.
// ,如果不存在,说明只有他的父节点是当前子树的根节点,当前递归执行完,指针指到父节点 执行3.
PreOrder(tree->rchild);
//3.接着递归判断父节点的右子树是不是下一个子树的根节点(就是判断右结点是否存在),
//存在把右子树当成根节点访问1.,不存在,说明只有父节点是它右子树的根节点,当前递归结束,
// 指针指向父节点,接着判断父节点的左子树是不是根节点 执行2
}
}
//NRL
void PreOrder_1(BitTree tree)
{
if(tree)
{
printf("%c ",tree->data);
PreOrder_1(tree->rchild);
PreOrder_1(tree->lchild);
}
}
//RLN
void InOrder_1(BitTree tree)
{
if (tree)
{
InOrder_1(tree->rchild);
printf("%c ",tree->data);
InOrder_1(tree->lchild);
}
}
//RNL 先找到每个小二叉树的最右边结点,然后在操作,再找最右结点,重复
void PostOrder(BitTree tree)
{
if (tree) //递归条件
{
PostOrder(tree->rchild); //找右子树的最右结点
PostOrder(tree->lchild);
printf("%c ",tree->data);
//PostOrder(tree->lchild)和PostOrder(tree->rchild)共同实现(就是递归啊,只有递归他们才能先后执行)找父节点的左子树的最右边结点
}
//这样即可遍历所有结点,并且还保证了,每次都从最右边结点处开始遍历
//明白这个思想,二叉树的所有问题就都是套这个思想了
//同时二叉树的问题基本上都是建立在遍历的基础上的,
//也就是说我们确定好了,遍历方法,然后填上遍历的代码,最后在加上要具体操作的代码即可
}
int main()
{
BitTree tree;
CreateBitTree(tree);
BitTree a = tree;
//PreOrder(tree);
PreOrder_1(a);
printf("
");
InOrder_1(a);
printf("
");
PostOrder(a);
printf("
");
free(tree);
return 0;
}
//总结
//所谓的,先序后序中序遍历都是遍历的根节点,本质上,因为二叉树中,每一个结点都是根节点
//只不过,他们唯一的区别就是,根节点的访问顺序不同,如RLN是先访问每一个小子树的右结点
//最后,要注意,递归算法都是解决的一个大问题的重复性小问题,所以,二叉树的递归遍历本质上都是依次遍历一个一个只有三个结点的小二叉树
//或者(有1个结点,2个结点的小二叉树)
//必须要理解上面总结的思想,你才算真正学会了,二叉树的递归遍历,一旦你学会了思想,那么剩下的二叉树操作都是在遍历上添加代码即可,
//只不过是二叉树遍历语句要稍加改变