(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

这篇具有很好参考价值的文章主要介绍了(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

3.3.1 遍历(先中后)

二叉树的遍历

先序遍历:

中序遍历

后序遍历

tips:

3.3.2 中序非递归遍历

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

中序遍历的非递归算法具体实现方法为:

3.3.3 层序遍历

难点

解决方法:

队列实现

思路

有如下二叉树作为例子:

遍历过程:(出队即printf)

思考:

3.3.4 遍历应用例子

1. 输出二叉树中的叶子结点

2. 求二叉树高度

3. 二元运算表达式树及其遍历

4. 由两种遍历序列确定二叉树


3.3.1 遍历(先中后)

二叉树的遍历

先序遍历:

遍历过程:

  1. 访问根结点
  2. 先序遍历其左子树(递归遍历,根结点左子树如果也有左右子树也要遍历)
  3. 先序遍历其右子树

既然需要递归遍历左右子树,我们设想以下如果直接用递归实现这个算法(伪码):

void PreOrderTraversal( BinTree BT )
{
     if( BT ) {
         printf(“%d”, BT->Data);
         PreOrderTraversal( BT->Left );
         PreOrderTraversal( BT->Right );
     }
}

若有二叉树为A(B(DF(E))C(G(H)I)),其先序遍历访问顺序为——A-B-D-F-E-C-G-H-I

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

中序遍历

遍历过程:

  1. 先序遍历其左子树
  2. 访问根结点
  3. 先序遍历其右子树

代码就直接将Printf放到两次递归中间即可

void PreOrderTraversal( BinTree BT )
{
     if( BT ) {
         PreOrderTraversal( BT->Left );
         printf(“%d”, BT->Data);
         PreOrderTraversal( BT->Right );
     }
}

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

后序遍历

遍历过程:

  1. 先序遍历其右子树
  2. 访问根结点
  3. 先序遍历其左子树
void PostOrderTraversal( BinTree BT )
{
    if( BT ) {
        PostOrderTraversal( BT->Left );
        PostOrderTraversal( BT->Right);
        printf(“%d”, BT->Data);
    }
}

 (浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

tips:

先序、中序和后序遍历过程:遍历过程中经过结点的路线一 样,只是访问各结点的时机不同。

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

3.3.2 中序非递归遍历

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

中序遍历是按左、根、右的顺序,所以以上一节的树为例:

  1. 在一开始遇到A,A有左子树,所以将A放入堆栈
  2. 下一个要处理的是A的左子树B,B也有左子树,所以再把B放到堆栈里
  3. 下一个是B的左子树D,D没有孩子,D放入堆栈后就要出栈了,随后B出栈
  4. 此时B这棵树左、根都遍历完了,接下来处理右子树F。
  5. F有左子树,所以先把F放入堆栈
  6. F的左子树E没有孩子,E入栈然后出栈F再出栈,最后A的左子树处理完毕,A也出栈
  7. 此时遍历顺序为DBEFA,接着处理A的右子树
  8. A的右子树C,C有左子树,存入栈,处理其左子树
  9. G没有左子树,所以先入栈后出栈
  10. G有右子树H(中序遍历顺序),H没有左子树,入栈后紧接着出栈
  11. 处理完C的左子树,C可以出栈
  12. C有右子树I,I没有左子树,入栈后紧接着出栈
  13. 最后遍历顺序即为:DBEFAGHCI

中序遍历的非递归算法具体实现方法为:

  • 遇到一个结点就将其压入栈,并遍历其左子树(若有左子树的话),
  • 当左子树遍历完毕,就从栈顶弹出这个结点并访问它
  • 按结点右指针去遍历这个结点的右子树
void InOrderTraversal( BinTree BT )
{
    BinTree T=BT;
    Stack S = CreatStack( MaxSize ); /*创建并初始化堆栈S*/
    
    while( T || !IsEmpty(S) ){
        while(T){
            /*一直向左并将沿途结点压入堆栈*/
            Push(S,T);
            T = T->Left;
        }
        if(!IsEmpty(S)){
        T = Pop(S); /*结点弹出堆栈*/
        printf(“%5d”, T->Data); /*(访问)打印结点*/
        T = T->Right; /*转向右子树*/
        }
    }
}

也可推知,先序遍历也能用非递归实现,修改printf位置即可

void PreOrderTraversal( BinTree BT )
{
    BinTree T=BT;
    Stack S = CreatStack( MaxSize ); /*创建并初始化堆栈S*/
    
    while( T || !IsEmpty(S) ){
        while(T){
            /*一直向左并将沿途结点压入堆栈*/
            Push(S,T);
            printf(“%5d”, T->Data); /*第一次碰到就打印*/
            T = T->Left;
        }
        if(!IsEmpty(S)){

        T = Pop(S); /*结点弹出堆栈*/
        T = T->Right; /*转向右子树*/
        }
    }
}

但后序遍历不能简单挪动位置实现,因为后序遍历在操作完左右子树后需要返回到根结点,而且是在第三次经过根结点时将其pop出去,所以实现它需要用到两个堆栈

1. 初始化两个堆栈s1和s2,将根节点压入s1中。
2. 从s1中弹出栈顶节点,将其压入s2中。
3. 如果该节点有左子节点,则将左子节点压入s1中。
4. 如果该节点有右子节点,则将右子节点压入s1中。
5. 重复步骤2到步骤4,直到s1为空。
6. 从s2中依次弹出节点并输出,即可得到后序遍历序列。

void PostOrder(BinTree BT)
{
    BinTree T = BT;
    stack S = createstack();
    while(T || IsEmpty(S)){
        while(T){
            push(S, T); 
            T = T->Left;
        }
        if(top(S)->Right != NULL){
            T = top(S)->Right;
            continue;
        }
        T = pop(S);
        printf("%5d", T->data);
        while(top(S)->Right == T){
            T = pop(S);
            printf("%5d", T->data);
         }
        T = top(S)->Right;
}

3.3.3 层序遍历

难点

除了先中后序,我们还有一种遍历方式是层序遍历。二叉树是一个二维结构,而遍历的序列是一个线性结构,遍历二叉树的本质是将一个二维结构变成一维线性结构。

而难点在于,只有通过父结点才能访问到左右孩子结点,再通过子结点来访问子结点的左右孩子结点,因此如果变成线性结构,线性就意味着一个点只与另一个点有关,而子结点会有两个,当访问了一个子结点之后另一个子结点该怎么处理?

解决方法:

用一个存储结构来保存暂时不访问的结点。如堆栈、队列

队列实现

思路

遍历从根结点开始,首先将根结点入队,然后开始执行循环:

  • 从队列中取出一个元素
  • 访问该元素所指结点
  • 若该元素所指结点的左、右孩子结点非空, 则将其左、右孩子的指针顺序入队。

有如下二叉树作为例子:

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

遍历过程:(出队即printf)

A入队,第一个元素为A,队列为A

A出队,将A的左右儿子BC入队,此时第一个元素为B,队列为BC

B出队,将B的左右儿子DF入队,此时第一个元素为C,队列为CDF

C出队,将C的左右儿子GI入队,此时第一个元素是D,队列为DFGI

D出队,D没有左右儿子,此时第一个元素是F,队列为FGI

F出队,将F的左儿子E入队,此时第一个元素是G,队列为GIE

G出队,将G的右儿子H入队,此时第一个元素是I,队列为IEH

I出队,EH都没有子结点,依次出队

出队顺序为:A B C D F G I E H,序列恰好是每一层的结点顺序

void LevelOrderTraversal ( BinTree BT )
{
    Queue Q;
    BinTree T;

    if ( !BT ) return; /* 若是空树则直接返回 */
    Q = CreatQueue( MaxSize ); /*创建并初始化队列Q*/
    AddQ( Q, BT );

    while ( !IsEmptyQ( Q ) ) {
        //Step1
        T = DeleteQ( Q );
        //step2
        printf(“%d\n”, T->Data); /*访问取出队列的结点*/
        //Step3
        if ( T->Left ) AddQ( Q, T->Left );

        if ( T->Right ) AddQ( Q, T->Right );
    }
}

思考:

若将层序遍历中的队列实现修改为堆栈实现,是否也是一种遍历方法?

是的,改为堆栈后一般称其为深度优先遍历,简单来说就是访问根结点,再依次访问其左右子树直到遍历完整棵树。

3.3.4 遍历应用例子

1. 输出二叉树中的叶子结点

思路:在遍历算法中加入一个“检测该结点左右子树是否都为空”,即可得知是否为叶子结点

//以前序遍历为例
void PreOrderPrintLeaves( BinTree BT )
{
    if( BT ) {
        //若左右子树为空,则打印结点
        if ( !BT-Left && !BT->Right )
        {
            printf(“%d”, BT->Data );
        }
        PreOrderPrintLeaves ( BT->Left );
        PreOrderPrintLeaves ( BT->Right );
    }
}

2. 求二叉树高度

二叉树的总高度=左右子树的最大高度+1,因此要求二叉树总高度,需要先知道左右子树的高度。后序遍历的遍历顺序显然很符合这样的算法

int PostOrderGetHeight( 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 */
}

3. 二元运算表达式树及其遍历

如下表达式树,其作用是对左右两颗树做根结点运算

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历

4. 由两种遍历序列确定二叉树

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

答案是不能,必须要知道中序遍历+其他任意遍历序列才行

若已知先序和中序遍历序列,如何确定一颗二叉树?

思路:已知先序第一个结点是根结点,只要在中序中找到一样的结点,就能在中序遍历序列中分割开左子树和右子树,再递归使用这个方法分解全部结点。

(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历文章来源地址https://www.toymoban.com/news/detail-464017.html

到了这里,关于(浙大陈越版)数据结构 第三章 树(上) 3.3 二叉树的遍历的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据库系统工程师——第三章 数据结构与算法

    数据结构是指 数据元素的集合 及 元素间的相互关系和构造方法 ,结构就是元素之间的关系。在数据结构中,元素之间的相互关系是数据的逻辑结构。按照逻辑关系的不同将数据结构分为线性结构和非线性结构,其中,线性结构包括线性表、栈、队列、串,非线性结构主要包

    2024年02月04日
    浏览(55)
  • 【全解析 | PTA】浙大版《Python 程序设计》题目集-第三章

    一、判断题 1.\\\'age\\\'+23不是正确的表达式。T 2 . 列表可以用find()函数来搜索数据是否在列表中。F         find()函数是字符串处理函数;Python find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果包含子

    2024年04月15日
    浏览(48)
  • C++[第三章]--程序结构

    class里面的函数实现可以放到class外面实现,class里面声明即可。所以这部代码可以放到.h文件中如: 在cpp里面实现这些函数即可如: 多个cpp文件出现同名函数(非类里面的函数)会混淆。 定义:.h/.cpp文件中: 调用者源文件中: 直接使用: a::fun, a::fun2 using声明: using a::fun; // 以后

    2024年02月15日
    浏览(25)
  • c语言修炼第三章--结构体

    目录 前言 3.1结构体的含义以及语法 3.1.1结构体含义 3.1.2结构体语法形式 3.1.2结构体变量的创建和初始化 3.2结构体成员的类型 3.3结构体的成员访问 3.3.1.操作符 3.3.2-操作符 3.4结构体传参 小伙伴们大家好!欢迎继续和菜菜酱学习c语言呐!之前菜菜酱有事所以耽误啦,废话不多

    2024年02月16日
    浏览(31)
  • 第三章-Ethernet/IP帧结构

    所有封装报文应由一个 24 字节的固定长度报文头和一个可选的数据部分组成。封装报 文的总长度(包括报文头)应限制在 65535 字节以内。其结构如下。 Command Length 表示报文数据的大小(以字节为单位),对于不含数据的报文,则为0。 报文的总长度=Length的数值+24字节。 S

    2024年02月01日
    浏览(36)
  • 第三章-Java的基本程序设计结构

      3.1一个简单的Java语言程序  这是程序虽然很简单,但是所有的Java程序都具有这种结构,因此还是值得花一些时间来研究的。首先,Java区分大小写。如果出现了大小写拼写错误(例如:将main拼写成Main),程序将无法运行。 下面逐行的查看这段源代码。pubilc称为访问修

    2024年02月03日
    浏览(40)
  • Python基础练习题--第三章 控制结构

    目录 1025:【例3.1】购买笔记本 1026:【例3.2】判断奇偶 1027:【例3.3】区间测速 1028:【例3.4】飞船速度 1029:练3.1最大优惠价 1030:练3.2判断闰年 1031:练3.3最适宜运动心率2 1032:【例3.5】计程票 1033:【例3.6】BMI健康信息 1034:练3.4  区间测速2 1035:练3.5  购买笔记本2 【题

    2024年02月07日
    浏览(42)
  • 大数据之路——数据同步(第三章)

       如第一章所述,我们将数据采集分为日志采集和数据库数据同步两部分。数据同步技术更通用的含义是不同系统间的数据流转,有多种不同的应用场景。主数据库与备份数据库之间的数据备份,以及主系统与子系统之间的数据更新,属于同类型不同集群数据库之间的数据

    2024年01月25日
    浏览(28)
  • 第三章 HL7 架构和可用工具 - 使用 HL7 架构结构页面

    通过 HL7 架构页面,可以导入和查看 HL7 版本 2 架构规范。要显示此页面,请从主页中选择互操作性 互操作 HL7 v2.x HL7 v2.x 架构结构。有关使用此页面的一般信息,请参阅在产品中使用虚拟文档中的“使用架构结构页面”。 HL7 模式页面提供了一个附加选项卡:消息类型。此选

    2024年02月15日
    浏览(29)
  • 第三章作业:关系数据库

    同一个关系模型的任意两个元组值(C ) A 必须全同 B 可全同 C 不能全同 D 以上都不是 设W=R∞S,且W,R,S的元组个数分别为p,m,n,那么三者之间满足 D。 A. p(m+n) B. p≤(m+n) C. p(m×n) D. p≤(m×n) σF1(σF2(E))与 A 等价。 A. σF1∧F2(E) B. σF1(E) C. σF2(E) D. σF1∨F2(E) 设关系R和S的属性个数分别

    2023年04月25日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包