第4章第2节 二叉树的基本操作(递归实现)

二叉树的递归遍历

所谓二叉树的遍历,本质上就是沿某条搜索路径访问树中的每个结点,使得每个节点均被访问一次,而且仅被访问一次。

由二叉树的基本定义可以知道,遍历一颗二叉树首先必须决定对根结点(N),左子树(L),右子树(R)的访问顺序,按照先遍历左孩子再遍历右孩子的原则,常见的遍历次序有先序遍历(NLR)中序遍历(LNR)后序遍历(LRN)三种遍历算法。

在这里使用做个简单的例子来说明下。

一.先序遍历

先序遍历的操作过程为:

Created with Rapha?l 2.1.0开始二叉树是否为空?结束访问根结点先序遍历左子树先序遍历右子树yesno

那么先序遍历的结果应该为

A->B->D->F->C->E

这样根据定义便可以写出相应的算法描述

void PreOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        printf("%c",T->data);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

二.中序遍历

中序遍历的过程为:

Created with Rapha?l 2.1.0开始二叉树是否为空?结束先序遍历左子树访问根结点先序遍历右子树yesno

那么中序遍历的结果应该为

B->F->D->A->C->E

这样根据定义便可以写出相应的算法描述

void InOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        InOrder(T->lchild);
        printf("%c",T->data);
        InOrder(T->rchild);
    }
}

三.后序遍历

后序遍历的过程为:

Created with Rapha?l 2.1.0开始二叉树是否为空?结束先序遍历左子树先序遍历右子树访问根结点yesno

那么后序序遍历的结果应该为

F->D->B->E->C->A

这样根据定义便可以写出相应的算法描述

void PostOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        printf("%c",T->data);
    }
}

上述算法中,递归遍历左、右子树的顺序都是固定的,只是访问根结点的顺序不同。不管采用哪种遍历算法,每个节点都访问一次且仅访问一次,故时间复杂度都是O(n)。在递归遍历中,递归工作栈的栈深度恰好为树的深度,所以在最坏的情况下,二叉树有n个结点且深度为n的单支树,遍历算法的空间复杂度为O(n)。

完整代码见附件


附件

//AB#DF###C#E##
#include<stdio.h>
#include<stdlib.h>

#define MaxSize 100
typedef char ElemType;
typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

BiTree CreateBiTree(BiTNode*);
void PreOrder(BiTNode*);
void InOrder(BiTNode*);
void PostOrder(BiTNode*);

int main(int argc, char* argv[]){
    BiTNode *T;
    T=(BiTNode*)malloc(sizeof(BiTNode));
    T=CreateBiTree(T);
    PreOrder(T);
    printf("\n");
    InOrder(T);
    printf("\n");
    PostOrder(T);
    printf("\n");
    return 0;
}

BiTree CreateBiTree(BiTNode* T){
    ElemType x;
    scanf("%c",&x);
    if(x==‘#‘){
        return T;
    }
    T=(BiTNode*)malloc(sizeof(BiTNode));
    T->data=x;
    T->lchild=CreateBiTree(T->lchild);
    T->rchild=CreateBiTree(T->rchild);
    return T;
}

void PreOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        printf("%c",T->data);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

void InOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        InOrder(T->lchild);
        printf("%c",T->data);
        InOrder(T->rchild);
    }
}

void PostOrder(BiTNode* T){
    if(T==NULL){
        return;
    }else{
        PostOrder(T->lchild);
        PostOrder(T->rchild);
        printf("%c",T->data);
    }
}
时间: 2024-08-02 04:35:32

第4章第2节 二叉树的基本操作(递归实现)的相关文章

第4章第3节 二叉树的基本操作(非递归实现)

二叉树的非递归遍历 上一节二叉树的递归遍历中简单介绍了二叉树的递归遍历的实现方式,本节主要介绍二叉树的非递归遍历实现,继续引用上节的例子来说明下. 一.先序遍历 二叉树先序遍历的访问顺序为:根结点->左孩子->右孩子.简单的说,对于任意一个结点,均可以看作是根结点,直接对其访问,如果访问完成后,左孩子不为空,则可以将该左孩子再次看成一个新的根结点,那么就又回到开始,访问根结点,访问左孩子,如果左孩子为空时,访问它的右孩子.对于一般程序而言,递归程序转为非递归程序需要引入栈这个数据结构,可以参考

第四章第4节 二叉树特殊节点个数统计

为了方便说明二叉树的递归传值过程,这里首先给出一个基本的二叉树结构. 图中值为NULL的节点实际是不存在的,故与父亲节点之间的连接用灰色的虚线表示.只是为了便于说明,才假设了一个NULL的空节点. 以下图中,黄色的线表明了传值的方向:绿色的数值表明了子节点传到父亲节点时的值,即根据递归公式计算便可. 一.统计二叉树中度为0的节点个数(递归/非递归) 递归方式实现 二叉树中,度为0则表明该节点的左孩子.右孩子均为空,根据二叉树的特性,最容易想到的便是采用递归方式实现该答案.首先列出基本递归公式:

第1章第2节练习题2 非递归删除指定结点

问题描写叙述 在带头结点的单链表L中.删除全部值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法实现以上的操作 算法思想 使用指针p指向数据域为x的结点.使用指针pre指向指针p所指结点的前驱结点,从前向后进行遍历.假设指针p指向的结点的数据域为x,则删除.假设指针p指向的结点的数据域不为x,继续向后遍历就可以. 算法描写叙述 void DelNodeX(LNode *head, ElemType x) { LNode *pre=head; LNode *p=head->next;

Git帮助文档阅读笔记----第二章-第五节---打标签

本节我们一起来学习如何列出所有可用的标签,如何新建标签,以及各种不同类型标签之间的差别. 列显已有的标签 直接运行 git tag 即可: 可以用特定的搜索模式列出符合条件的标签.在 Git 自身项目仓库中,有着超过 240 个标签,如果你只对 1.4.2 系列的版本感兴趣,可以运行下面的命令: $ git tag -l 'v1.4.2.*' v1.4.2.1 v1.4.2.2 v1.4.2.3 v1.4.2.4 新建标签 轻量级的(lightweight) 含附注的(annotated)(建议

NHibernate.3.0.Cookbook第一章第六节Handling versioning and concurrency的翻译

NHibernate.3.0.Cookbook第一章第六节Handling versioning and concurrency的翻译 第一章第二节Mapping a class with XML第一章第三节Creating class hierarchy mappings第一章第四节Mapping a one-to-many relationship第一章第五节Setting up a base entity class Handling versioning and concurrency

Git帮助文档阅读笔记----第二章-第四--节远程仓库的使用

管理这些远程仓库,以便推送或拉取数据 添加远程库 移除废弃的远程库 管理各式远程库分支 定义是否跟踪分支 查看当前的远程库 可以用 git remote 命令,它会列出每个远程库的简短名字 也可以加上 -v 选项(译注:此为 --verbose 的简写,取首字母),显示对应的克隆地址: 如果有多个远程仓库,此命令将全部列出.比如在我的 Grit 项目中,可以看到: 添加远程仓库 要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行 git remote add [shortname

软件构造 第三章第五节 ADT和OOP中的等价性

第三章第五节 ADT和OOP中的等价性 1.==与equals ==是引用等价性 :而equals()是对象等价性. == 比较的是索引.更准确的说,它测试的是指向相等(referential equality).如果两个索引指向同一块存储区域,那它们就是==的.对于我们之前提到过的快照图来说,==就意味着它们的箭头指向同一个对象. equals()操作比较的是对象的内容,换句话说,它测试的是对象值相等(object equality).在每一个ADT中,equals操作必须合理定义 2.等价性

软件构造 第七章第四节 调试

第七章第四节 调试 [bug的常见类型] 数学bug:例如 零除法,算术溢出 逻辑bug:例如 无线循环和无限递归 源头bug:例如 使用了为被定义的变量.资源泄漏,其中有限的系统资源如内存或文件句柄通过重复分配耗尽而不释放.缓冲区溢出,其中程序试图将数据存储在分配存储的末尾. 团队工程bug:例如 评论过时或者评论错误.文件与实际产品的区别 ## 调试的基本过程 Debug是测试的后续步骤:测试发现问题,debug消除问题:当防御式编程和测试都无法挡住bug时,我们就必须进行debug了: D

二叉树遍历,递归,栈,Morris

一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归.非递归.Morris遍历) 2015年01月06日 |  分类:数据结构 |  标签:二叉树遍历 |  评论:8条评论 |  浏览:6,603次 二叉树遍历是二叉树中最基本的问题,其实现的方法非常多,有简单粗暴但容易爆栈的递归算法,还有稍微高级的使用栈模拟递归的非递归算法,另外还有不用栈而且只需要常数空间和线性时间的神奇Morris遍历算法,本文将对这些算法进行讲解和实现. 递归