https://www.cnblogs.com/nancymake/p/6516933.html
先讲解图中几种遍历:
其实每种遍历的规则都是针对于节点来说,即每个节点需要满足相应的规则。
先序遍历:
顺序为根、左、右,则每个节点需满足此条件。从整体来看,毫无疑问A是根节点,那么之后是左边B,我们需要将B所有后代遍历完整体才是左,那么对于B则又需要遵从此规则,即B、D、E,而因为此时E有子节点,那么对于E而言,则是E、H,所以根、左边遍历完成是A、B、D、E、H,那么右边也是同样道理,根、左、右,C、F、G,因为F有子节点,对于F而言,就是F、I,所以右边完成后是C、F、I、G。总的就是A、B、D、E、H、C、F、I、G。
中序遍历:
顺序为左、根、右,则每个节点需满足此条件。从整体来看,最左边为D,那么根据顺序左、根、右,即D、B、E,因为E有子节点,那么对于E而言,则是H、E。所以左边遍历完成即为D、B、H、E,当然过后是A。现在到右边,也是满足顺序左、根、右,即F、C、G,因为F有子节点,对于F而言,就是F、I,所以左边完成后是F、I、C、G。总就是D、B、H、E、A、F、I、C、G。
后序遍历:
顺序为左、右、根,则每个节点需满足此条件。最左边为D,那么根据顺序左、右、根,即D、E、B,因为E有子节点,那么对于E而言,则是H、E。所以左边遍历完成即为D、H、E、B。现在到右边,也是满足顺序左、右、根,即F、G、C,因为F有子节点,对于F而言,就是I、F,所以左边完成后是I、F、G、C。当然最后是A。总就是D、H、E、B、I、F、G、C、A。
其实上面仅仅是自己理解的方法,也有不同的理解,我们也可以从下往上看。这里就不再赘述。
对于实现来说,我们怎么用代码描述这样的一种数据结构,这值得思考。
我们可以分析,其实就是让结点之间产生一种关联,每个节点就是一个数据,只不过需要用指针来记录节点间的关系以及联系。
代码如下:
#include "pch.h"
#include <iostream>
#include <stdio.h>
#include <string.h>
#define TElemType char
int top = -1; // top变量时刻表示栈顶元素所在位置
// 定义结点类型
typedef struct BiTNode {
TElemType data; // 数据域
struct BiTNode *lchild, *rchild; // 左右孩子指针
}BiTNode, *BiTree;
// 构造一棵二叉树
void CreateBiTree(BiTree *T)
{
*T = (BiTNode*)malloc(sizeof(BiTNode)); // 根结点
(*T)->data = 'A';
(*T)->lchild = (BiTNode*)malloc(sizeof(BiTNode)); // 左指针
(*T)->rchild = (BiTNode*)malloc(sizeof(BiTNode)); // 右指针
(*T)->lchild->data = 'B';
(*T)->lchild->lchild= (BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
(*T)->lchild->rchild->data = 'C';
(*T)->lchild->rchild->lchild = NULL;
(*T)->lchild->rchild->rchild = NULL;
(*T)->rchild->data = 'D';
(*T)->rchild->lchild = (BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->lchild->data = 'E';
(*T)->rchild->lchild->lchild = NULL;
(*T)->rchild->lchild->rchild = NULL;
(*T)->rchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
(*T)->rchild->rchild->data = 'F';
(*T)->rchild->rchild->lchild = NULL;
(*T)->rchild->rchild->rchild = NULL;
(*T)->lchild->lchild->data = 'G';
(*T)->lchild->lchild->rchild = NULL;
(*T)->lchild->lchild->lchild = NULL;
}
// 前序和中序遍历使用进栈函数
void Push(BiTNode **a, BiTNode *elem) {
a[++top] = elem;
}
// 出栈
void Pop() {
if (top == -1)
return;
top--;
}
// 输出结点本身数据
void PrintElem(BiTNode *elem) {
printf("%c ", elem->data);
}
// 获取栈顶元素
BiTNode *GetTop(BiTNode **a)
{
return a[top];
}
// 先序遍历递归算法
void PreOrderTraverse(BiTree tree)
{
BiTNode *a[20];
BiTNode *p;
Push(a, tree);
while (top != -1) {
p = GetTop(a);
Pop();
while (p) {
PrintElem(p);
if (p->rchild) //如果该结点有右孩子,右孩子进栈
Push(a, p->rchild);
p = p->lchild;
}
}
}
// 中序遍历递归算法
void InOrderTraverse(BiTree tree)
{
BiTNode *a[20]; // 定义一个顺序栈
BiTNode *p; // 临时指针
Push(a, tree); // 根结点进栈
while (top != -1) // top !=-1说明栈内不为空,程序继续执行
{
while ((p = GetTop(a)) && p) // 取栈顶元素,且不能为NULL
{
Push(a, p->lchild); //将该结点的左孩子进栈,如果没有左孩子,NULL进栈
}
Pop(); // 跳出循环,栈顶元素肯定为NULL,将NULL弹栈
if (top != -1) {
p = GetTop(a); //取栈顶元素
Pop();
PrintElem(p);
Push(a, p->rchild); // 将p指向结点的右孩子进栈
}
}
}
///
// 后序遍历非递归算法
typedef struct SNode {
BiTree p;
int tag;
}SNode;
// 后序遍历使用进栈函数
void postpush(SNode *a, SNode sdata) {
a[++top] = sdata;
}
//后序遍历
void PostOrderTraverse(BiTree Tree) {
SNode a[29];
BiTNode *p;
int tag;
SNode sdata;
p = Tree;
while (p || top != -1)
{
while (p) {
sdata.p = p;
sdata.tag = 0; // 由于遍历是左孩子,设置标志位为0
postpush(a, sdata); // 入栈
p = p->lchild; // 以该 结点为根结点,遍历左孩子
}
sdata = a[top];
Pop();
p = sdata.p;
tag = sdata.tag;
if (tag == 0) // tag==0 说明该 结点还没有遍历它的右孩子
{
sdata.p = p;
sdata.tag = 1;
postpush(a, sdata); // 更改结点标志位,重新入栈
p = p->rchild; // 该结点右孩子为根结点,重新循环
}
else
{
PrintElem(p);
p = NULL;
}
}
}
int main()
{
BiTree Tree;
CreateBiTree(&Tree);
printf("二叉树前序遍历结果为(DLR):\n");
PreOrderTraverse(Tree);
printf("\n二叉树中序遍历结果为(LDR):\n");
InOrderTraverse(Tree);
printf("\n二叉树后序遍历结果为(LRD):\n");
PostOrderTraverse(Tree);
return 0;
}