数据结构第三周笔记(7)——树(上)(慕课浙大版本--XiaoYu)

113 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

3.3.2 中序非递归遍历

二叉树的非递归遍历

中序遍历非递归遍历算法

非递归算法实现的基本思路: 使用堆栈

这里建议看视频的演示,非常形象

1.遇到一个结点,就把它压栈,并去遍历它的左子树;
2.当左子树遍历结束后,从栈顶弹出这个结点并访问它;
3.然后按其右指针再去中序遍历该结点的右子树
​
以下是完整代码实现演示
void InOrderTraversal(BinTree BT)
{
    BinTree T = BT;//把BT赋给临时变量T
    Stack S = CreateStack(MaxSize);//创建并初始化堆栈
    while(T || !IsEmpty(S) ){//树不空且堆栈不空
        while(T){//判断堆栈空不空
            //一直向左并将沿途结点压入堆栈
            Push(S,T);//把T压入堆栈S中
            T = T->Left;//然后把T往左挪,就是边挪边把结点压到堆栈里面去,压到底T为NULL就退出来
        }
        if(!IsEmpty(S)){
            T = Pop(S);//结点弹出堆栈
            printf("%5d",T->Data);//(访问)打印结点
            T = T->Right;//转向右子树
        }
    }
}
​
ppoopoppoo错误
    
PPOPOOPPOO正确
    第二次碰到同一个的时候就print出来

image-20220701114302678

先序遍历的非递归遍历算法?

把上方那个算法中if中的printf("%5d",T->Data)移到while(T)中Push的后面

后序遍历非递归遍历算法?

3.3.3 层序遍历

二叉树遍历的核心问题:二维结构的线性化(变成一维的)

1.从结点访问其左、右儿子结点
2.访问左儿子后,右儿子结点怎么办?
    1.需要一个存储结构保存暂时不访问的结点
    2.存储结构:堆栈、队列

队列实现

遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队、访问该结点、其左右儿子入队

image-20220701122430994

image-20220701122450231

image-20220701122514520

image-20220701122530744

image-20220701122549970

image-20220701122603151

最后结果就是:层序遍历 => A B C D F G I E H

//代码实现
void LevelOrderTraversal(BinTree BT)
{
    Queue Q; BinTree T;
    if(!BT) return;//若是空树直接返回
    Q = CreateQueue(MaxSize);//创建并初始化队列Q
    AddQ(Q,BT);//把BT这个根节点放到Q这个队列里
    while(!IsEmptyQ(Q)){
        T = DeleteQ(Q);//抛出元素赋给T就是一个指针
        printf("%d\n",T->Data);//访问去除队列的结点
        if(T->Left) Add(Q,T->Left);//左右儿子放到队列里去
        if(T->Right) AddQ(Q,T->Right);
    }
}

3.3.4 遍历应用例子

】遍历二叉树的应用:输出二叉树中的叶子结点

在二叉树的遍历算法中增加检测结点的"左右子树是否都为空"

void PreOrderPrintLeaves(BinTree BT)
{
    if(BT){
        if(!BT-Left && !BT->Right)
            printf("%d",BT->Data);
        PreOrderPrintLeaves(BT -> Left);
        PreOrderPrintLeaves(BT -> Right);
    }
}

【例】求二叉树的高度

image-20220701124015460

void PreOrderGetHeight(BinTree BT)
{
    int HL,HR,MaxH
    if(BT){
        HL = PostOrderGetHeight(BT->Left);//求左子树的深度,这两个都是递归哦
        HR = PostOrderGetHeight(BT->Right);//求右子树的深度
        MaxH = (HL > HR) ? HL :HR;//取左右子树较大的深度
        return (MaxH + 1);//返回树的深度
    }
    else return 0;//空树深度为0
}

【例】二元运算表达式树及其遍历

image-20220701124745933

中缀表达式是不准的,会收到运算符优先度的影响,其它都是准的

解决中缀表达式不准的问题:左子树开始前加个左括号,结束后加个右括号,通过加括号的形式解决优先度问题

【例】由两种遍历序列确定二叉树

已知三种遍历中的任意两种遍历序列,能否唯一确定一颗二叉树呢?

答案:必须要有中序遍历才行

没有中序的困扰:

1.先序遍历序列:A B

2.后序遍历序列:B A

会发现符合条件的树不止一个

先序第一个是根后序最后一个是根

image-20220701125607995

问:已知有颗5个结点的二叉树,其前序遍历序列是a????,中序遍历序列是a????,可以断定:

image-20220701125653916

答案: 该树根结点是a,且没有左子树