数据结构(1):树

树的定义:

树(Tree)是n(n>=0)个结点的有限集。当n=0时为空树,在任一课非空树种:

  1. 有且仅有一个特定的称为根的结点;

  2. 当n>1时,其余结点可分为m(m>0)个互不相交的有限集,其中每一个集合本身又是一棵树,并且称为根的子树;

相关概念:

  • 度:结点拥有的子树数量;度为0的结点是叶子结点
  • 结点的祖先:从根到该结点所经过的分支上的所有结点
    树的深度:从根所在的层到最下面叶子结点的层次数

存储结构:

在使用树结构描述实际问题时,大多数不是二叉树,更多的是普通的树结构,在存储之间具有普通树结构的数据时,经常使用的方法有3种:

  • 双亲表示法
  • 孩子表示法
  • 孩子兄弟表示法

双亲表示法:
取一块连续的内存空间,在存储每个结点的同时,各自都附加一个记录其父结点位置的变量。
在树结构中,除了树根外,每个结点都只有一个父结点(叫“双亲结点”)。

代码表示:

#define TElemType int
#define Tree_Size 100
//孩子表示法
typedef struct CTNode
{
  int child;  //链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
  struct CTNode *next;
}*ChildPtr;

typedef struct 
{
  TElemType data;  //结点的数据类型
  ChildPtr firstchild;  //孩子链表的头指针
}CTBox;

typedef struct
{
  CTBox nodes[Tree_Size];  //存储结点的数组
  int n, r;  //结点数量和树根的位置
}CTree;

例如,使用孩子表示法存储图 1 (A),存储效果如图 2:

图 1 双亲表示法
当算法中需要在树结构中频繁地查找某结点的父结点时,使用双亲表示法最合适。当频繁地访问结点的孩子结点时,双亲表示法就很麻烦,采用孩子表示法就很简单。

孩子表示法:

将树中的每个结点的孩子结点排列成一个线性表,用链表存储起来。对于含有 n 个结点的树来说,就会有 n 个单链表,将 n 个单链表的头指针存储在一个线性表中,这样的表示方法就是孩子表示法。如果结点没有孩子(例如叶子结点),那么它的单链表为空表。

代码表示:

#define TElemType int
#define Tree_Size 100
//孩子表示法
typedef struct CTNode
{
  int child;  //链表中每个结点存储的不是数据本身,而是数据在数组中存储的位置下标
  struct CTNode *next;
}*ChildPtr;

typedef struct 
{
  TElemType data;  //结点的数据类型
  ChildPtr firstchild;  //孩子链表的头指针
}CTBox;

typedef struct
{
  CTBox nodes[Tree_Size];  //存储结点的数组
  int n, r;  //结点数量和树根的位置
}CTree;

例如,使用孩子表示法存储图 1 (A),存储效果如图 2:
在这里插入图片描述

使用孩子表示法存储的树结构,正好和双亲表示法相反,适用于查找某结点的孩子结点,不适用于查找其父结点。可以将两种表示方法合二为一,存储效果如图 3:
在这里插入图片描述

使用孩子表示法存储的树结构,正好和双亲表示法相反,适用于查找某结点的孩子结点,不适用于查找其父结点。可以将两种表示方法合二为一,存储效果如图 3:
在这里插入图片描述
其中孩子指针域,表示指向当前结点的第一个孩子结点,兄弟结点表示指向当前结点的下一个兄弟结点。

代码表示:

#define ElemType int
typedef struct CSNode
{
  ElemType data;
  struct CSNode *firstchild, *nextsibling;
}CSNode, *CSTree;

通过孩子兄弟表示法,普通树转化为了二叉树,所以孩子兄弟表示法又被称为“二叉树表示法”或者“二叉链表表示法”。
例如,用孩子兄弟表示法表示图 1 (A)的普通树,存储结果为:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值