树的概念
树是一个非线性的数据结构,前面我们学习的顺序表、链表等等等等,他们的逻辑结构都是成一条线的,都是所有元素都是排成一条的;而树他是有多个分支的,是发散的。
树是由n(n>=0)个有限节点所组成的一个具有层次关系的集合;之所以把这个集合叫做树是因为它看起来很像一颗倒过来的树(我个人感觉更像倒着的灌木丛),也就是说,他的根是朝上的,叶子是朝下的。
- 有一个特殊的节点,根节点,根节点是没有前置节点的
- 除了根节点,其他节点都被分为了M(M > 0)个不相交的集合 ,每个集合又是一颗结构与树类似的子树,每颗子树的根节点有且仅有一个前置节点(父节点),但可以有0个或多个后续节点(子节点)
- 所以,树是由递归定义的。(一颗树分为根和子树,子树又可以分为根和子树,子树的子树又可以分为根和子树……直到没有可以分的子树了)。
注意,再说一次:在树形结构中,子树是不能有交集的,有就不是树形结构!!!(而是图型结构)
树的相关概念
我们要想理解树,就必须要知道树的相关概念(标红的是重点)
结点的度:一个结点含有的子树的个数称为该结点的度(有多少个“儿子”); 如上图:A的为6
叶结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、Q...等结点为叶结点
非终端结点或分支结点:度不为0的结点; 如上图:D、E、J…等为分支结点
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
树的度:一棵树中,最大的结点的度称为树的度(哪个节点的“儿子”最多,度就该节点的“儿子”数量); 如上图:树的度为6
结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;
树的高度或深度:树中结点的最大层次(分支最深); 如上图:树的高度为4
堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
森林:由m(m>0)棵互不相交的树的集合称为森林;
树的表示
数据结构是为了管理数据,存储和查找数据是最基本的两个功能。
树当然也要有这两个功能
方法一(指针数组)
因为前面我们知道了树的度这一概念,假设这个树的度是N,就代表这颗树必然有个节点有N个“儿子”,所以我们在设计结构的时候,设计一个长度为N的指针数组,就可以用指针数组来存储子节点,将该节点的所以子节点都存放在这个数组里了。
#define N x //x为树的度
typedef int DataType;
struct Node
{struct Node* subs[N]; DataType data;
};
但是但是 ,这样会造成空间的浪费 ,树是不会出现所有节点都有度的,就拿上面的例子来,可以看到,这个树的度为6,但有很多的节点它的度是到不了6(还有些就没有度),但是这块空间是固定会开辟的,不管你是否有度,不管你度的数量多不多,都会固定开辟一块长度为N的指针数组。
方法二(左孩子右兄弟)
也就是说,在一个树的结构体中,只会有两个指针,一个称为左孩子指针,指向最左边的子节点;一个称为右兄弟指针,指向右边的亲兄弟 。
typedef int DataType;
struct Node
{struct Node* firstChild1; //第一个孩子struct Node* pNextBrother; //下一个兄弟的节点DataType data;
};
树在实际中的运用(表示文件系统的目录树结构)
结语
最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言,也可以前往我的主页看更多好文哦(点击此处跳转到主页)。
如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!