• 数据结构(C语言版)---树


    1、树:n个结点的有限集,n=0时为空树。

    1)特点:

    (1)有且仅有一个特定的称为根的结点。

    (2)有若干个互不相交的子树,这些子树本身也是一棵树。

    (3)树的根结点没有前驱结点,除根结点外的所有结点有且只有一个前驱结点。

    (4)树中所有结点可以有零个或多个后继结点。
    2)通俗的定义:

    (1)树由节点和边组成。
    (2)每个结点只有一个父结点,但可以有多个子结点。
    (3)但有一个结点例外,该结点没有父结点,该结点称为根结点。

    3)树分类:

    (1)一般树:任意一个结点的子结点的个数都不受限制。

    (2)二叉树:任意一个结点的子结点个数最多两个,且子结点的位置不可更改,二叉树的子树有左右之分。
    (3)森林:n个互不相交的树的集合。

    4)树的基本性质

    (1)树中的结点数等于所有结点的度数+1。

    (2)度为m的树中第i层上至多有mi-1个结点。

    (3)高度为h的m叉树至多有(mh-1)/(m-1)个结点。

    (4)具有n个结点的m叉树的最小高度为logm(n(m-1)+1)。
    2、专业术语:

    1)深度:树中结点的最大层次,即从根节点到最底层节点的层数,根结点是第一层。
    2)叶子结点:没有子结点的结点。
    3)非终端结点:实际上就是非叶子结点。
    4)度:子结点的个数。结点的度:结点拥有的子树个数。树的度:树内各结点的度的最大值。

    5)层次:从根开始定义起,根为第一层,根的孩子为第二层。

    6)结点的高度:从叶子结点开始自底向上逐层累加。

    7)路径长度:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目为长度。

    8)树的路径长度:从树根到每个结点的路径长度之和。

    9)树的带权路径长度:树中所有叶子结点的带权路径长度之和,记作WPL。

    3、树的存储:
    1)双亲表示法:采用一组连续空间来存储每个结点,同时在每个结点中增设一个伪指针,指示双亲结点在数组中的位置。

    (1)优点:求父节点方便。

    (2)双亲表示法的存储结构描述
    typedef struct {
     int data;
     int parent;
    }PTNode;
    typedef struct {
     PTNode nodes[Maxsize];
     int n;
    }PTree;
    2)孩子表示法:将每个结点的孩子结点都用单链表链接起来形成一个线性结构,n个结点就有n个孩子链表(叶子结点的孩子链表为空表)。

    (1)优点:求子节点方便。
    3)孩子兄弟表示法(二叉树表示法):每个结点包含三部分:结点值、指向结点第一个孩子结点的指针、指向结点下一个兄弟结点的指针。

    (1)优点:求父节点和子节点都很方便,方便实现树转化为二叉树;
    (2)具体转化方法:保证任意一个结点的左指针域指向它的第一个孩子、右指针域指向它的下一个兄弟,只要能满足此条件,就可以把一个普通树转化为二叉树。
    (3)特点:一个普通树转化成的二叉树一定没有右子树,因为根结点没有兄弟。

    (4)孩子兄弟表示法的存储结构类型描述
    typedef struct CSNode {
     int data;
     struct CSNode *firstchild, *nextsibling;
    }CSNode,*CSTree;
    计算以孩子兄弟表示法存储的森林的叶子数
    int leaves(CSTree t)
    {
     if (t == NULL)
     {
      return 0;
     }
     if (t->firstchild == NULL)
     {
      return 1 + leaves(t->nextsibling);
     }
     else
     {
      return leaves(t->firstchild) + leaves(t->nextsibling);
     }
    }
    递归求以孩子兄弟表示法表示的树的深度
    int height(CSTree t)
    {
     int l, r;
     if (t == NULL)
     {
      return 0;
     }
     else
     {
      l = height(t->firstchild);
      r = height(t->nextsibling);
      if (l + 1 > r)
      {
       return l + 1;
      }
      else
      {
       return r;
      }
     }
    }
    4、森林的存储:先把森林转化为二叉树,再存储二叉树。

    5、树操作:
    1)树的遍历
    (1)先根遍历
                    先访问根结点、再按从左到右的顺序遍历根结点的每棵子树。
    (2)后根遍历
                    先按从左到右的顺序遍历根结点的每棵子树、再访问根结点。

    2)森林的遍历

    (1)先序遍历

                     先访问森林中第一棵树的根结点,再先序遍历第一棵树中根结点的子树森林,再先序遍历除去第一棵树之后剩余的树组成的森林。

    (2)中序遍历

                     先中序遍历森林中第一棵树中根结点的子树森林,再访问森林中第一棵树的根结点,再中序遍历除去第一棵树之后剩余的树组成的森林。

    6、树应用:
    1)树是数据库中数据组织的一种重要形式。
                         操作系统子父进程的关系和面对对象语言中类的继承关系本身就是一棵树。
    2)并查集的结构定义

    int UFSets[Maxsize];
    (1)初始化
    void initial(int S[])
    {
     for (int i = 0; i < Maxsize; i++)
     {
      S[i] = -1;
     }
    }
    (2)查找并返回包含元素e的树的根
    int find(int S[], int e)
    {
     while (S[e]>=0)
     {
      e = S[e];
     }
     return e;
    }
    (3)求两个不想交子集合的并集
    void uniontree(int S[], int root1, int root2)
    {
     S[root2] = root1;
    }
    7、赫夫曼树(最优树):一棵带权路径长度最短的树,没有度为1 的结点,一棵有n0个叶子结点的树,共有2n0-1个结点。

    1)构造过程

    (1)将n个结点作为n棵含一个结点的二叉树。

    (2)从中选取两棵根结点权值最小的树作为新结点的左、右子树,新结点的权值为左右子树根结点的权值之和。

    (3)重复。

    2)特点

    (1)每个初始结点最终成为叶结点,权值越小的结点到根结点的路径长度越大。

    (2)构造过程中共新建了n-1个结点,所以结点总数为2n-1个。

    (3)不存在度为1 的结点。

  • 相关阅读:
    让Dapper读写分离
    让Dapper在一个项目中支持多种库
    用implicit和explicit打通两种类型
    foreach和IEnumerable+yield和IEnumerator
    顶级语句
    用NSubstitute来mock
    BenchmarkDotNet性能测试
    让Dapper支持Mock
    我的注释那去了?
    2、一日一程序之百钱买百鸡问题
  • 原文地址:https://www.cnblogs.com/xqy1874/p/12751767.html
Copyright © 2020-2023  润新知