风也温柔

计算机科学知识库

java二叉树的遍历算法 《算法与数据结构基础》学习笔记05_01——非线性结构_树、二叉树、二叉树的遍历

  本文章只是本人个人学习笔记,如有错误,欢迎批评指正

  以下是本人自学的视频

  概要:非线性结构5.1 树

  树(Tree)——n个结点。递归定义:由根(Root)和子树()组成

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  树的其他表现形式

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  5.1.2 树的基本术语

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

  5.1.3 树结构和线性结构的比较3

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  5.2 树——二叉树

  二叉树————结点的度最多为2的树,孩子分别叫左子树、右子树,孩子的顺序不能互换

  二叉树可以是空集合,且左右子树可以为空树

  为什么要研究二叉树:一般的树很复杂,而二叉树是最简单的树,规律性强。任何树都可与二叉树相互转换

  注意:二叉树与树的最主要差别(也因其而是两者概念不同)————即使只有一个孩子,二叉树也要定义该孩子是左子树还是右子树;看下图例子

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  5.2.2 二叉树的5种基本形态

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  5.2.3 二叉树的性质

  性质1:二叉树在第

  层最多有

  个结点,最少有 1 个结点

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  性质2:深度为

  的二叉树,最多有

  个结点,最少有

  个结点。

  性质3:二叉树的总边数

  ,总结点数

  ,度2结点数

  ,度1结点数

  ,度0结点(叶子)数

  。

  总边数

  总结点数

  叶子数 与 度2结点数的关系:

  遍历树 算法_二叉树的递归遍历算法_java二叉树的遍历算法

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

  5.2.4 特殊的二叉树——满二叉树、完全二叉树

  5.2.4.1 满二叉树

  满二叉树:所有结点都在的树。即深度

  ,有

  个结点的二叉树

  满二叉树特点:

  5.2.4.2 完全二叉树

  完全二叉树:结点编号和同深度的满二叉树相同的二叉树。满二叉树是特殊的完全二叉树

  完全二叉树特点:

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  完全二叉树的性质

  具有

  个结点的完全二叉树的深度

  。(补充:

  :表示不大于x的最大整数,即floor(x))完全二叉树的编号关系:

  结点编号

  ,则其双亲结点编号为

  ,左孩子编号

  ,右孩子编号

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  5.2.5 二叉树的顺序存储

  1.按编号存储:从上到下,从左到右java二叉树的遍历算法,表示数组下标

  2.注!!!:即使子树为空,也为其编号,但是该数组位置存储空。目的就是使数组下标与树编号一一对应,可根据数组恢复二叉树原样

  3.二叉树顺序存储类型定义

   #define MAXTSIZE 100

  4.二叉树顺序存储缺点:对于非满二叉树,浪费空间大。适合完全二叉树

  5.2.6 二叉树的链式存储——二叉链表

  1.二叉链表

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  2.二叉树链式存储类型定义

   typedef struct BiNode {

        TElemType data;            // 数据域
        struct BiNode *Ichild, *rchild;        // 指针域:左右孩子指针

  3.补充:三叉链表

  新增个指针域:指向前驱

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  5.3 遍历二叉树

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  遍历————顺着一条路径巡访二叉树的结点,每个结点访问一次

  二叉树的遍历通过递归实现

  5.3.2 三种遍历方式

  子树按照:从左到右遍历

  将二叉树拆分成 逐级递减的二叉树,依次执行上述操作

  执行到下一结点后都要重新开始执行3个操作,而不是直接访问该结点

  1.先序遍历——根左右

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  2.中序遍历

  右图:将BEL是A的左子树,所以BEL访问后才A才右子树;同样,E的左子树访问完后(为空),才E,才右子树L;

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  3.后序遍历

  右图:二叉树拆分

  拆分A:BEL——A——DHMIJ

  拆分B:EL——B——空

  拆分E:空——E——L——————【按照左右根的方式输出LE

  EL输出完后,按照左右根的方式输出B

  BEL输出完后,按照左右根的方式输出,右子树是DHMIJ,需要拆分

  拆分D:HMI——D——J

  拆分H:M——H——I——————【按照左右根的方式输出MIH

  H输出完后java二叉树的遍历算法 《算法与数据结构基础》学习笔记05_01——非线性结构_树、二叉树、二叉树的遍历,按照左右根的方式输出,JD(注:若J还有子树,则还需再之前拆分J)

  D输出完后,输出A

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  例题:二叉树表示算数表达式

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  5.3.3 已知遍历次序反推二叉树

  【已知先序、中序】or 【已知中序、后序】java二叉树的遍历算法,可以确定二叉树;【已知先序、后序】,不能确定二叉树

  1.【已知先序、中序】

  先序:判断根结点(首端为根结点)

  中序:判断左右子树

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

  2.【已知中序、后序】

  后序:判断根结点(末尾为根结点)

  中序:判断左右子树

  5.3.4 遍历二叉树的实现——递归算法

  存储结构:二叉链表

  实现方式:递归遍历

  三种访问共性:访问路径相同,只是访问时机不同

  时间复杂度

  ————每个结点只访问依次

  最大空间复杂度

  ————递归到最远,栈占用最大辅助空间

  1.【先序遍历 DLR】

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

   //【先序遍历DLR————递归算法】

    int PreOrderTraverse(BiTree T) {
        if(T == NULL) return 1;        // 若空二叉树
        else {                // ——————根左右DLR——————
    <p>![java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法][22]

            visit(T);            // 访问根结点
            PreOrderTraverse(T->lchild);    // 回调递归:遍历左子树
            PreOrderTraverse(T->rchild);    // 回调递归:遍历右子树
        }

</p>
  2.【中序遍历 LDR】

  遍历树 算法_二叉树的递归遍历算法_java二叉树的遍历算法

   //【中序遍历LDR————递归算法】

    int InOrderTraverse(BiTree T) {
        if(T == NULL) return 1;        // 若空二叉树
        else {                // ——————左根右LDR——————
            InOrderTraverse(T->lchild);    // 回调递归:遍历左子树
            visit(T);            // 访问根结点
            InOrderTraverse(T->rchild);    // 回调递归:遍历右子树
        }

  3.【后序遍历 LRD】

  遍历树 算法_java二叉树的遍历算法_二叉树的递归遍历算法

   //【后序遍历LRD————递归算法】

    int PostOrderTraverse(BiTree T) {
        if(T == NULL) return 1;        // 若空二叉树
        else {                // ——————左右根LRD——————
            PostOrderTraverse(T->lchild);    // 回调递归:遍历左子树
            PostOrderTraverse(T->rchild);    // 回调递归:遍历右子树
            visit(T);            // 访问根结点
        }

  5.3.5 遍历二叉树的实现——非递归算法

  【中序遍历LDR】为例

  实现方式——栈

  遍历树 算法_java二叉树的遍历算法_二叉树的递归遍历算法

   //【中序遍历LDR————非递归算法,栈实现】

    int InOrderTraverse(BiTree T) {
        BTNode *p, *q;        // 新建指针
        SqStack S;         // 新建栈
        InitStack(S);        // 初始化栈
        p = T;                // p指针指向根结点
        while(p || !StackEmpty(S)) {    // 若p指针非空 or 栈非空
            if(p) {            // 若p非空
                Push(S, p);    // 让p指向的元素地址 入栈
                p = p->lchild;    // p 指向左子树
            }
            else {
                Pop(S, q);        // 出栈,栈顶元素的地址存在q中
                visit(q);        // 访问出栈的元素
                p = q->rchild;        // p指向被访问元素的右子树
            }
        }
        return 1;

  5.3.6 二叉树的层次遍历

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

  按照编号遍历:从上到下,从左到右

  实现方式:队列

  (根结点入队、结点出队、出队结点的孩子入队)

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

   //【二叉树的层次遍历————队列实现】

    void LevelOrder(BiTree T) {        
        BTNode *p = T;        // 新建指针,指向二叉树根结点
        SqQueue qu;        // 新建循环队列
        InitQueue(qu);        // 初始化队列
        enQueue(qu, p);        // 根结点地址入栈
        while(!QueueEmpty(qu)) {    // 队非空,则循环
            deQueue(qu, p);        // 出队,出队元素地址存储在p中      
            visit(p->data);        // 访问出队结点
            if(p->lchild != NULL)        
                enQueue(qu, p->lchild);        // 让出队结点左孩子入队
            if(p->rchild != NULL)
                enQueue(qu, p->rchild);        // 让出队结点右孩子入队
        }

  5.3.7 遍历二叉树的应用

  1.【二叉树的建立——递归遍历实现】

  遍历的操作:先序遍历,输入结点的信息,若输入#表示该结点为空

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

   【二叉树的建立——递归遍历实现】

     int CreateBiTree(BiTree &T) {   // 传入链二叉树
         char ch;
         cin >> ch;
         if(ch == &#39;#&#39;)   T = NULL;   // 该二叉树为空
         else {
              T = new BiTNode;   // 新建二叉树
              T->data = ch;      // 传入字符数据到二叉树根结点
              CreateBiTree(T->lchild);   // 递归:构造左子树
              CreateBiTree(T->lchild)    // 递归:构造右子树
         }
         return 1;

  2.【二叉树的复制——递归遍历实现】

  已知二叉树,将其复制一份

   【二叉树的建立——递归遍历实现】

    int CreateBiTree(BiTree &T) {    // 传入链二叉树
        char ch;
        cin >> ch;
        if(ch == &#39;#&#39;)    T = NULL;    // 该二叉树为空
        else {
             T = new BiTNode;    // 新建二叉树
             T->data = ch;        // 传入字符数据到二叉树根结点
             CreateBiTree(T->lchild);    // 递归:构造左子树
             CreateBiTree(T->lchild)    // 递归:构造右子树
        }
        return 1;

  二叉树的递归遍历算法_遍历树 算法_java二叉树的遍历算法

  3.【计算二叉树深度——递归遍历实现】

  当前结点的深度:计算左子树深度、和右子树深度,取大者+1(通过递归的回调计算上方结点的深度)

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

   //【二叉树的复制——递归遍历实现】

    void Copy(BiTree T, BiTree &NewT) {    // 输入参数:已知树,新树
        if(T == NULL) NewT = NULL;    // 若为空树
        else {
            NewT = new BiTNode;    // 新建树
            NewT-data = T->data;    // 根结点赋值
            Copy(T->lchild, NewT->lchild);        // 递归:复制左子树
            Copy(T->rchild, NewT->rchild);        // 递归:复制右子树
        }

  4.【计算二叉树结点总数——递归遍历实现】

  当前二叉树结点总数:左子树结点总数+右子树结点总数+1(通过递归的回调计算大二叉树的结点总数)

   //【计算二叉树结点总数——递归遍历实现】

    int NodeCount(BiTree T) {
        if(T == NULL) return 0;        // 空树的结点总数为0
        else
            return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
            // 递归回调:计算当前结点的结点总数

  5.【计算二叉树的叶子结点数——递归遍历实现】

  当前二叉树叶子结点总数:左子树结点总数+右子树结点总数(通过递归的回调计算大二叉树的叶子数)——

   //【计算二叉树的叶子结点数——递归遍历实现】

    int LeadCount(BiTree T) {
        if(T == NULL) return 0;        // 若为空树
        if(T->lchild == NULL && T->lchild == NULL)
            return 1;    // 若不为空树,且无左右子树
        else
            return LeadCount(T->lchild) + LeadCount(T->rchild);
            // 递归回调:计算当前结点的叶子结点数

  5.4 线索二叉树

  二叉链表一定有n+1个空的指针域

  1.利用二叉链表的n+1个指针域——线索化:

  二叉树的递归遍历算法_java二叉树的遍历算法_遍历树 算法

  2.线索二叉树( Tree)——线索化后的二叉树

  线索二叉树的二叉链表还需增设2个标志域 ltag,rtag——用于标识指向孩子还是前驱后继

  3.线索二叉树的定义

   //【线索二叉链表】

    typedef struct BiThrNode {
        ElemType data;        // 数据域
        int ltag, rtag;        // 标志位
        struct BiThrNode *lchild, *rchild;        // 指针域

  遍历树 算法_java二叉树的遍历算法_二叉树的递归遍历算法

  java二叉树的遍历算法_二叉树的递归遍历算法_遍历树 算法

  java二叉树的遍历算法_遍历树 算法_二叉树的递归遍历算法

  补充:线索二叉树仍然会有空指针,可以增设头结点,让这些空结点指向头结点,类似于循环链表

  遍历树 算法_java二叉树的遍历算法_二叉树的递归遍历算法

  文章来源:https://zhuanlan.zhihu.com/p/461372599