数据结构中的树 基础知识讲解

引言

原文链接:树的基本概念 希望点进去的小伙伴关注一下我的公众号哟,文末有二维码,谢谢!

这篇文章讲的是树的基本概念,二叉树在下一篇文章中讲。

树这种数据结构在生活中很常见,比如公司的组织结构图、文件系统等。当有大量数据时,链表的线性访问速度是最慢的,因此树这种结构有着极其重要的地位。

1、树的定义

线性结构属于一对一的结构,而树属于一对多的结构。

树是n(n>=0)个结点的有限集,n=0称为空树;并且在任意一颗非空树中:

  • 有且仅有一个根结点

  • 当n>1时,又能分为m个(m>0)个子树

下图就不满足树的定义,因为子树间存在交叉。

图片

2、结点

结点的一些概念:

  • 树的结点=1个数据元素+若干个指向子树的指针。

  • 结点的度:结点拥有的子树个数,度=0为叶子结点。除根结点外度!=0的结点为分支结点或内部结点。

  • 树的度:最大的结点的度。比如有三个结点,度分别为4,、5、6,那么树的度就是6。

  • 孩子结点:一个结点有多个孩子结点

  • 双亲结点:为什么不叫父或母?因为一个结点只有一个父结点,索性叫双亲结点。

  • 兄弟结点:即两个结点有同一双亲。

  • 祖先和子孙:这个就不解释了

结点的层次、堂兄弟(这个概念不怎么重要)如下图所示。最大层次称为树的深度(或高度)。

图片

线性结构和树结构的区别:

图片

3、树的存储结构

前面已经了解了树和结点的一些基本概念,并且已经知道了树是一对多的结果,那么这种一对多如何在计算机中存储呢?有如下表示法:

  • 双亲表示法

  • 孩子表示法

  • 孩子兄弟表示法

3.1、双亲表示法

假设现在有这样一棵树,如下图所示。

图片

那么根据双亲表示法,可以用如下数据表示这棵树的逻辑关系。

下标 data parent

0

-1

1

0

2

0

1

2

2

3

3

3
4

该表可以采用顺序存储结构,每一行对应一个结点,该结点存储两部分内容:结点值和双亲结点指针。

这种存储方式很容易找到某一结点的双亲结点,其时间复杂度为O(1),但是要找某一结点的所有孩子结点,必须要遍历整个表才行!

3.2、孩子表示法

即每个结点存储结点的数据和指向孩子的指针。

但是每个结点的度是不同的,那么孩子指针设置多少个合适呢?有以下几种方案:

  • 统一设成最大值,即树的度,但这样会造成空间浪费,特别是树中的结点的度差别很大的时候。

  • 孩子指针个数等于结点的度,但需要一个额外位置来存储该结点的孩子指针个数,但这种方案虽然避免了空间浪费,但需要额外维护一个数值。

上述两种方案都有缺点,根本原因在于每个结点的孩子指针是固定的,那将孩子指针设计成动态扩展的不就行了,因此可以采用数组+链表的设计方式,如下图所示。

图片

当有n个结点时,数组的长度为n,并且每个数组元素都延伸了一条单向链表来存储它的孩子。

但是这种结构需要遍历整棵树才能知道某个结点的双亲,因此可以在每个数组元素中存储该结点的双亲,如下图所示。

图片

3.3、孩子-兄弟表示法

前面两种表示法的思路是:要么存储结点的孩子,要么存储结点的双亲。而孩子-兄弟表示法,则存储的是结点的第一个孩子和结点右边的兄弟。

如果想查找某个结点的所有孩子,则首先可以迅速查找它的第一个孩子,然后根据第一个孩子,可以找到这个孩子右边的兄弟,依次类推,就可以找到该结点所有的孩子。

但是,如果想找到某个结点的双亲呢?如果有必要的话,可以对某个结点增加一个parent指针。

孩子-兄弟表示法如下图所示。

图片

这种表示法有一个好处就是,因为每个结点除了数据之外,只存储孩子和兄弟两个指针,因此很容易将上图转化为一颗二叉树,如下图所示。即使是再复杂的树也能转化为二叉树。这样就可以利用二叉树的特性和算法来处理这棵树了。


 

图片

觉得写得不错的小伙伴,扫码关注一下我的公众号吧,谢谢呀!

猜你喜欢

转载自blog.csdn.net/xl_1803/article/details/111587680