• 树和森林知识


    1、树的存储结构

    *******、双亲表示法

    在这种表示方法中,以一组连续的存储单元存储树的结点,每个结点除了数据域data之外 ,还附设一个parent域以指示器其双亲结点的位置

    //--------------------------------双亲表示法存储结构定义----------------------------
    #incluude<stdilo.h>
    #define MAXSIZE 100;
    typedef struct PNode{        //树的结点定义 
    	ElemType data;           //数据元素 
    	int parent;              //指向双亲的指针 
    }PNode;
    typedef struct{              //树的类型定义       
    	PNode node[MAXSIZE];     //双亲表示
    	int length;              //当前结点的个数 
    }PTree; 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这种存储结构利用了每个结点的(除根以外)只有唯一的双亲的性质。在这种情况下,求取双亲的结点十分方便,也很容易求得树的根,但是求结点的孩子时需要遍历整个存储结构!

    *******、孩子表示法(顺序表+链表)

    孩子表示法的用途很多,在第六章图的存储结构中就是使用孩子表示法实现邻接表的存储结构!

    //--------------------------------孩子表示法存储结构定义----------------------------
    #include
    #define MAXSIZE;
    typedef struct CTNode{
    	int child;                     //孩子结点存在数组中的位置
    	struct CTNode *next;           //下一个孩子 
    }CTNode; 
    typedef struct CTBox{
    	ElemType data;                 //父节点数据         
    	struct CTNode *FirstChild;     //第一个孩子    
    }CTBOX;
    typedef struct CTree{
    	CTBox nodes[MAXSIZE];    
    	int n,r;                        //结点数和根的位置 
    }CTree; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    如果想看孩子表示法在图中的应用,请点击此处

    *******、孩子兄弟法

    孩子兄弟表示将也就是二叉链表表示法,但是在二叉链表的基础上可以将结点的左指针修改为结点指向其第一个孩子的指针,将右指针修改为结点指向第一个孩子的兄弟结点的指针!

    //--------------------------------孩子兄弟法表示法存储结构定义----------------------------
    #include
    typedef struct CSNode{
    	int data;                                    //数据元素
    	struct CSNode *FirstChild,*NextBorther;      //第一个孩子和右兄弟指针
    }CSNode,*CSTree; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    可以看到使用这种存储结构有利于找到结点孩子等操作!当然如果再加入一个指向父节点的指针域有利于找到当前结点的父节点!但是对于这种存储结构有一个更大的好处是我们可以将一般的树转换为二叉树来处理!利用二叉树的各种算法实现对一般树的处理!因此孩子兄弟表示在树的存储结构中是一种比较常用的存储方式!

    2、树与二叉树的转化

    因为树的实质是使用二叉树的存储结构来存储的,所以对于树转化为二叉树只需要按照如下操作步骤即可:
    (1)、确定根节点
    (2)、确定根节点的第一个孩子结点,将其链接在根节点的左孩子
    (3)、确定第一个孩子结点的右兄弟,将其链接在左兄弟的右孩子,循环执行(3),直到第一个孩子结点没有右兄弟,如果有,就将其链接在前一个左兄弟的右孩子下面
    (4)、重复(1)、(2)、(3)直到树中所有的结点都被处理完!
    按照上面的思想,可以得到每一个根节点的第一个左孩子转换到二叉树中一定是左孩子,如果左孩子还有其他兄弟结点,转换到二叉树中一定是第一个左孩子的右孩子!但是对于树中最上面的根节点,有一没有兄弟结点,所以,其转换为二叉树之后 一定是没有左孩子的!
    因此二叉树转换为树,其实上是树转换为二叉树的逆过程!
    在这里插入图片描述

    3、森林与二叉树的转化

    在这里插入图片描述
    可以看到将森林转换为二叉树需要执行两步操作
    **********、首先需要将森林内部的每一棵树转换为二叉树,需要用到如何将树转换为二叉树的操作!
    **********、然后将森林内部的二叉树按照顺序拼装成一棵完整的二叉树即可!
    **********、森林中的第一棵子树转换为二叉树的左子树,其余子树转换为二叉树的右子树!

    4、树和森林的转化

    树和森林的转换其实是上面操作的步骤的逆过程!不论是树转换为森林还是二叉树转换为森林!

    5、树和森林的遍历

    *******、树的遍历(普通树)

    中序遍历是对于二叉树而言:
    中序遍历左子树,访问根结点,中序遍历右结点。
    在普通树中并不一定只有左右两颗子树,所以在普通树中没有中序遍历!
    因此普通树有下面三种遍历方式
    在这里插入图片描述

    (1)、先根遍历
    普通树先根遍历的方式和二叉树先根遍历的方式是一样的,所以上面先根遍历的结果是 R A D E B C F G H K
    (2)、后根遍历(其实是森林转换而来二叉树的中序遍历,其实也可以直接像二叉树的后根遍历一样直接遍历也能得到这个次序)
    在这里插入图片描述

    普通树的后根遍历和其转换为二叉树之后的中序遍历结果是一样的,所以对于普通树后根遍历的次序可以由转化而来的二叉树求得:D E A B G H K F C R
    (3)、层序遍历
    普通树层序遍历的方式和二叉树正序遍历的方式是一样的,所以上面树的层序遍历结果是 R A B C D E F G H K

    *******、森林的遍历

    在这里插入图片描述

    (1)、先序遍历
    **********、首先访问森林中第一棵树的根节点
    **********、然后先序遍历第一棵树的根节点的子树森林
    **********、先序遍历除去第一棵树之后剩余树构成的森林!
    直到所有的子树森林都被先序遍历完成!
    可以看到每一棵子树的遍历和二叉树的遍历是一样的!
    对上面的森林完成先序遍历如下:A B C D E F G H I J
    (2)、中序遍历(其实是森林转换为二叉树的中序遍历,当然也可以直接将森林中的每一棵子树进行后根遍历的次序也能得到这个结果)
    森林可以转换为二叉树,所以在森林中森林的中序遍历其实就是森林转换为二叉树之后该二叉树的中序遍历!
    所以上面的森林对应的二叉树如下:
    在这里插入图片描述
    所以森林的中序遍历结果就是二叉树中中序遍历的结果为 : B C D A F E H J I G

  • 相关阅读:
    网络安全面试
    数据结构哈希表(散列)Hash,手写实现(图文推导)
    sql server卡慢问题定位和排查
    JVM中的STW(Stop The World)
    java毕业设计儿童教育系统Mybatis+系统+数据库+调试部署
    下班后根本联系不上,这样的员工可以辞退吗
    “创新启变 聚焦增长”极狐(GitLab)媒体沟通会,共话智能时代软件开发新生态
    如何配置和使用自己的私有 Docker Registry
    Linux分区指南
    力扣 757. 设置交集大小至少为2
  • 原文地址:https://blog.csdn.net/qq_51691366/article/details/126334545