chapter §10 二叉树的遍历(递归和非递归实现)

一、结点定义

typedef int ElemType;
typedef struct BiTNode {
    ElemType data; //数据域
    struct BiTNode *lchild; //左孩子
    struct BiTNode *rchild; //右孩子
} BiTNode, *BiTree;

二、树的遍历

1、递归写法

先序遍历:先访问根结点,再先序遍历左子树,再先序遍历右子树。

void PreOrderTraverse(BiTree T) { //先序遍历
    if (T != NULL) {
        visit(T); //访问根结点
        PreOrderTraverse(T->lchild);//访问左子树
        PreOrderTraverse(T->rchild);//访问右子树
    }
}

中序遍历:先中序遍历左子树,再访问根结点,再中序遍历右子树。

void InOrderTraverse(BiTree T) { //中序遍历
    if (T != NULL) {
        InOrderTraverse(T->lchild);//访问左子树
        visit(T); //访问根结点
        InOrderTraverse(T->rchild);//访问右子树
    }
}

后序遍历:先后序遍历左子树,再后续遍历右子树,最后访问根结点。

void PostOrderTraverse(BiTree T) { //后序遍历
    if (T != NULL) {
        PostOrderTraverse(T->lchild);//访问左子树
        PostOrderTraverse(T->rchild);//访问右子树
        visit(T); //访问根结点
    }
}
2、非递归写法

先序遍历:利用栈,令P等于根结点,作为工作结点,如果P非空或栈非空,则重复以下操作:如P非空,则访问P,然后将P入栈,再令P等于其左孩子;若P指向空,说明P已经到达最左边的结点的左孩子,且左孩子为空,则将栈顶元素出栈到P,此时P的左子树已访问完毕,接下来访问右子树,令P等于其右孩子,重复以上操作。

void PreOrderTraverse1(BiTree T) { //非递归先序遍历
    if (T == NULL) {
        return;
    }
    LinkStack S;
    initStack(S);//初始化链栈
    BiTree P = T;//P为工作结点
    while (P != NULL || !isEmpty(S)) { //P不空且栈非空
        if (P != NULL) {
            visit(P);//访问当前结点
            push(S, P);//当前结点入栈,因为右子树还未访问
            P = P->lchild;
        } else {
            pop(S, P);//左子树已为空,出栈
            P = P->rchild;//访问右子树
        }
    }
}

中序遍历:和先序遍历类似,只需将访问P的操作放到出栈后即可。即先一路将根结点及左下结点依次入栈,当达到最左下结点时,出栈并访问它,然后转向右子树。

void InOrderTraverse1(BiTree T) { //中序遍历
    if (T == NULL) {
        return;
    }
    LinkStack S;
    initStack(S);
    BiTree P = T;
    while (P != NULL || !isEmpty(S)) {
        if (P != NULL) {
            push(S, P);
            P = P->lchild;
        } else {
            pop(S, P);
            visit(P);
            P = P->rchild;
        }
    }
}

后序遍历:类比中序遍历,1、先沿着根节点,依次将左孩子入栈,直到左孩子为空。2、此时取栈顶元素P,由于要想访问当前结点P,则必须满足要么P的右孩子已经被访问,要么P的右孩子为空,因此可设置一个辅助指针r,用来指向最近一次访问过的结点。如果P满足上述条件,则可访问P,并将栈顶元素出栈,由于P此时已被访问,所以已P为根的子树均已被访问,且表示P的父节点的左子树已访问,所以接着向上回溯,对其父结点执行2。如果访问到P,其右孩子不为空,则令P等于其右孩子,继续执行1。

void PostOrderTraverse1(BiTree T) { //后序遍历
    if (T == NULL) {
        return;
    }
    LinkStack S;
    initStack(S);
    BiTree P = T;
    BiTNode *r = NULL;//记录最近访问过的结点
    while (P != NULL || !isEmpty(S)) {
        if (P != NULL) {
            push(S, P);//左孩子入栈
            P = P->lchild;
        } else {
            GetTop(S, P);//左孩子为空,取栈顶元素
            if (P->rchild == r || P->rchild == NULL) {//右孩子已被访问过或没有右孩子
                pop(S, P);//出栈
                visit(P);//访问
                r = P;//更新r
                P = NULL;//P置空,以便取下一个栈顶元素
            } else {
                P = P->rchild;//右孩子存在且未被访问,继续循环
            }
        }
    }
}
3、层次遍历

借助一个队列,先将根节点入队,若队列非空,则进行以下操作:队头元素出队,并访问,如其还有左孩子,则左孩子入队,若有右孩子,右孩子入队。反复执行,直到队列为空。

void LevelOrderTraverse(BiTree T) { //层次遍历
    LinkQueue Q;
    InitQueue(Q);  //初始化一个链队
    BiTree P;
    EnQueue(Q, T); //根结点入队
    while (!isEmpty(Q)) { //队列非空
        DeQueue(Q, P); //队头元素出队
        visit(P); //访问队头元素
        if (P->lchild != NULL) //左孩子非空
            EnQueue(Q, P->lchild); //左孩子入队
        if (P->rchild != NULL)//右孩子非空
            EnQueue(Q, P->rchild);//右孩子入队
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Missヾaurora

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值