树型结构(数据结构)

6.1树的基本概念

树型结构是区别于线性结构的另一大数据结构,它具有分支性层次性

树是由n(n>=0)个结点构成的有限集合。n=0的树称为空树;当n!=0时,树中的结点度应该满足下列条件:

  1. 有且仅有一个特定的结点称之为根
  2. 其余结点分成m(m>=0)个互不相交的有限集合,T1,T2,…,Tm,其中每一个集合又都是一颗树,称T1,T2,…,TM为根结点的子树。
  3. 以上是一个递归定义。

树的度:我们将一结点拥有的子女数称为该结点的度,树中所有结点度的最大值称为树的度。

叶子结点:称度为0的结点为终端结点或者叶子结点。

分支结点:称度不为0的结点为非终端结点或分支结点。

树枝:树中连接两个结点的线段称为树枝

路径:在树中,若从结点Ki开始沿着树枝自上而下能到达结点kj,则称ki到kj存在一条路径。路径的长度等于所经过的树枝数。

树中结点的层次:从树根开始定义,根节点为第1层,根的子女结点构成第2层,以此类推。若某结点kj位于第i层,则其子女就位于第i+1层。

树的深度或高度:称树中结点的最大层次数为树的深度或高度。

有序树:若树中任意结点的子树均看成是从左到右有次序的,不能随意交换,则称该树是有序树;否则称为无序树。

森林:由m(m>=0)颗互不相交的树构成的集合称为森林。森林和树的概念十分相近,一颗树中每个结点的子树所构成的几个即为一个森林,而在森林中的每棵树之上加一个共同的根,森林就成为了一棵树。

6.3树的存储结构

常用的树的存储结构有三种:双亲表示法、孩子表示法、孩子兄弟表示法

6.3.1双亲表示法

在树中,除根节点没有双亲外,其他每个结点的双亲是唯一确定的。故存储树中的结点应该包含两个信息:结点的值data和体现结点之间的相互关系的属性-----该结点的双亲parent。

可以将树中所有的结点存放在一个一维数组中。

#define MAXSIZE 100
typedef char datatype;
typedef struct node
{
    
    
    datatype data;
    int parent;
}node;
typedef struct tree
{
    
    
    node treelist[MAXSIZE];
    int length ,root;
}tree;

6.3.2孩子表示法

采用孩子表示法表示一棵树时,树中每个结点除了存储自身的值之外,还必须指出其所有子女的位置。 每个结点通常包含两个域:一个是元素的值域data,另一个为指针数组。数组中的每个元素均为一个指向该结点子女的指针;一颗m度的数,其指针数组的大小即为m

孩子表示法又分为三种:

  1. 指针方式的孩子表示法
  2. 数组方式的孩子表示法
  3. 链表方式的孩子表示法
1、指针方式的孩子表示法
#define m 3
typedef char datatype;
typedef struct node{
    
    
    datatype data;
    struct node *child[m];
}node ,*tree;
tree root;
2、数组方式的孩子表示法

为了查找方便,可以将树中的所有结点存储在一个一维数组中。

#define m 3
#define MAXSIZE 20   /*存放树节点的数组大小*/
typedef char datatype;
typedef struct node{
    
    
    datatype data;
    int child[m];
}treenode;
treenode tree[MAXSIZE];  /*存储树结点的数组*/
int root;   /*根节点的下标值*/
int length;  /*树中实际所含结点的个数*/
3、链表方式的孩子表示法

把每个结点的子女排列起来形成一个单链表,这样n个结点就形成n个单链表;而n个单链表的头指针又组成一个线性表,为了查找方便,可以使用数组方式加以存储。

#define MAXSIZE 50
typedef char datatype;
typedef struct cnode{
    
      /*孩子结点的类型*/
    int child;
    struct chnode *next;
}chnode,*chpoint;
typedef struct{
    
        /*树中,每个结点的类型*/
    datatype data;
    chpoint firstchild;
}node;
typedef struct {
    
        /*树的类型*/
    node treelist [MAXSIZE];
    int length ,root;
}tree;

6.3.3孩子兄弟表示法

即在存储树中每个结点时,除了包含该结点值域外,还设置两个指针域firstchild和rightsibling,分别指向该结点的第一个子女和其右兄弟,即以二叉链表方式加以存储。因此该方法也常称为二叉树表示法。

6.4树的遍历

树的遍历,就是按照某种规定的顺序访问树中的每个结点,且每个结点仅被访问一次。

树的遍历常分为3种:

  1. 树的前序遍历(根左右。如果根下还有根,则继续访问以下的根)
  2. 树的后序遍历(左右根。)
  3. 树的层次遍历

树的前序遍历和后序遍历的定义具有递归性,因此采用递归方式实现树的前、后序遍历,只要按照其各自规定的顺序,访问根节点时就输出根节点的值,访问子树时遍进行递归调用即可。

1、树的前序遍历
void preorder(tree p)
{
    
    
    int i;
    if(p!=NULL)
    {
    
    
        printf("%c",p->data);
        for(i=0;i<m;i++)
            preorder(p->child[i]);
    }
}
2、树的后序遍历
void postorder(tree p)
{
    
    
    int i;
    if(p!=NULL)
    {
    
    
        for(i=0;i<m;i++)    /*依次递归实现各个子树的后序遍历*/
            postorder(p->child[i]);
        printf("%c",p->data);   /*输出根节点的值*/
    }
}
3、树的前序遍历建立一颗3度树

返回根的地址

tree createtree()
{
    
    
    int i;
    char ch;
    tree t;
    if((ch=getchar())=='#')
        t=NULL;
    else
    {
    
    
        t=(tree)malloc(sizeof(node));
        t->data=ch;
        for(i=0;i<m;++i)
            t->child[i]=createtree();
    }
    return t;
}
4、树的层次遍历

队列(先进先出)思想:先访问第一层结点,若有子女,则将子女加入队列中;访问第二层结点时,将刚加入的结点出队。再将第二层结点的子女结点进队。。。。。重复上述过程。(队列中的每个元素均为在排队等待访问的结点)

思想:在树的层次遍历过程中,对于某一层上的每个结点的子女结点正好构成下一层的所有结点,接下来应该被访问的就是他们。树的层次遍历中首先访问的是根节点,因此初始时队列中仅包含根结点。只要队列不为空,就意味着还有结点未被访问。

void levelorder(tree t)
{
    
    
    tree queue[100];  /*存放等待访问的结点队列*/
    int f,r,i;        /*f ,r分别为队头、队尾指针*/
    tree p;
    f=0;r=1;queue[0]=t;
    while(f<t)     /*队列不为空*/
    {
    
    
        p=queue[f];
        f++;
        printf("%c",p->data);
        for(i=0;i<m;++i)
            if(p->child[i])
            {
    
    
                queue[r]=p->child[i];
                ++r;
            }
    }
}

6.5树的线性表示

6.5.1树的括号表示

  1. 若树T为空树,则其括号表示为空。
  2. 若树T只包含一个结点,其括号表示即为该结点本身。
  3. 如果不是上述情况,则表示为**A(B,C(F,G,H),D,E(J,I))**注意,有逗号!!!

6.5.2树的层号表示

设j为树中的一个结点,若为j赋予的一个整数值lev(j)满足以下两个条件:

  1. 如果结点i为j的后件,则lev(i)>lev(j)
  2. 如果结点i与j为同一结点的后件,则lev(i)=lev(j)

则称满足以上条件的整数值lev(j)为结点j的层号。

一个栗子

  1. 10A , 20B , 20C , 30F , 30G , 30H , 20D , 20E , 40J , 40I
  2. 1A , 2B , 2C , 5F , 5G , 5H , 2D , 2E , 3J , 3I

猜你喜欢

转载自blog.csdn.net/weixin_48931875/article/details/112406250