
Hi! 你们好,我是小小,咱们开始今天的内容,今天主要讲解什么是树。node
树的递归结构
从一张图中解释什么是树这张图,主要讲解关于cart这个单词的全部的可能组合,按照常理,须要先考虑三个字母的排列,而后对三个字母进行拆分,直到最后一个节点,这个过程就相似于树 到底什么是树web
什么是树
树是节点集合(A tree is a collection of nodes),面试
集合:集合是容许一个元素都没有的集合,称之为空集。数组
首先,集合是容许一个元素都没有的集合,称之为空集,那么书是否是也容许一个节点都没有的呢,是的,一个节点都没有的树,称之为空树,若是不是空的,则会存在根节点r和零个或更多非空子树,T1,T2.。。Tk,他们的根由来自r的有向链接,什么叫有向边,大体能够理解为箭头。用图的关系说明树的内部关系缓存
-
根节点(root)一棵树只有一个跟节点,全部的节点都在该节点的下面,尝试把图倒过来看,能够当作一个咱们平常见到的数的根部,在这里显然字母A就是这颗树的根节点。微信
-
子节点,父节点,一个节点,它对应的下面有连这的节点,那么被连着的节点就是这个节点的子节点,也叫作孩子,那么这个节点叫作被链接的节点的父亲,看图,B被A连这,因此B是A的一个孩子,同理,CDE等等这一行都是A的孩子,同时F,它连这K L M 同时被A连这,那么F是A的一个孩子,同时又是K L M 的父亲。数据结构
-
树叶:树叶就是那些没有孩子的节点,好比B,C,D等等,例以下图的绿色部分。
app
-
兄弟: 按照咱们的理解,同一个父母生的固然是兄妹,以下图所示,颜色相同的都是兄妹
maven
-
路径 咱们一样能够定义从父亲到他孩子的路径,下面的路径,咱们就取上图的一部分,一个子树,做为例子
好比,A->O的路径为A->E->J->O它的长度为3,实际为它的边数,图中红色的部分。编辑器
-
节点的深度:节点的深度指的是节点到树根的长度,看下图,咱们能够轻易的知道,j节点的深度为2,能够理解为 A-> E -> J 边长为2.显然,此时根节点的深度为0.
-
节点的高度:高度是从节点到叶子的最长路径,好比节点F的高度为1,显然全部叶子节点高度为0.
-
树的高度,树的高度是跟的高度,显然在这图中,树的高度为3,A->O
树的特色
-
按照正常的逻辑,一我的不能同时有两个父亲,因此树也同样,下图的两个就解释了这个问题 -
一颗正常的树,它的树枝是不会长成一个圆的,因此,树中,是不可能出现环形的。图中,红色箭头构成了一个环,因此都不是一颗树。
树的存储结构
树的存储结构有三种,分别为,双亲表示法,孩子表示法,孩子兄弟表示法。
双亲表示法
假设一组连续空间保存着树的特色,同时在每一个节点中,附带一个指示器表示双亲节点中链表的为位置,也就是说,每一个节点除了知道本身是谁之外,还知道他的双亲在哪里。其中data是数据域,存储结点的数据信息。而parent是指针域,存储该结点的双亲在数组中的下标。
//树的双亲表示法结点结构定义
#define MAX_TRUE_SIZE 100
typedef int TElemType //树结点的数据类型
//结点结构
typedef struct PTNode
{
TElemType data; //结点数据
int parent; //双亲位置
}PTNode
//树结构
typedef struct
{
PTNode nodes[MAX_TRUE_SIZE]; //结点数组
int r,n //根的位置和结点数
}PTree
有了这样的数据结构就能够来实现双亲表示法。因为根结点是没有双亲的,因此咱们约定根结点的位置域设置为-1,这也就意味着,咱们全部的结点都存有他双亲的位置。如图1-2中的树结构和表1-3中的树双亲表示。这样的存储结构,咱们能够根据结点的parent’指针很容易找到他的双亲结点,时间复杂度为O(1),直到parent为-1时,表示找到了树结点的根
孩子表示法
换一种彻底不一样的考虑方法,因为树中每一个结点可能有多棵子树,能够考虑用多重链表。每一个结点有多个指针域,其中每一个指针指向一颗子树的根结点,咱们把这种方法叫作多重链表的表示方法。不过,树的每一个结点的度,也就是他的孩子个数是不一样的,因此设计两种方法:
方案一
指针域的个数就等于树的度,树的度就是树各个结点度的最大值。其结构如图
其中data是数据域,child1到childd是指针域,用来指向该结点的孩子结点。对于图1-1来讲,树的度是3,因此咱们指针域个数就是3,

方案二
每一个结点指针域的个数等于该结点的度,咱们专门取一个位置来存储结点指针的个数。data为指针域,degree为度域,也就是存储该结点的孩子结点的个数
这就是咱们要说的孩子表示法,把每一个结点的孩子都排列起来,以单链表为存储结构,则n个结点有n个孩子链表,若是是叶子结点则此单链表为空。而后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组,
为此,设计两种存储结构,一个是孩子链表的孩子结点,
child是数据域,用来存储某个结点在表头数组中的下标。next是指针域,用来存储指向结点的下一个孩子结点的指针。另外一个是表头数组的表头结点。
data是数据域,存储某结点的数据信息,firstchild是头指针域,存储该结点的孩子链表的头指针。
//树的孩子表示法结构定义
#define MAX_TRUE_SIZE 100
typedef struct CTNode //孩子结点
{
int child;
struct CTNode *next;
}*ChildPtr;
//表头结构
typedef struct
{
TElemType data;
ChildPtr firstchild;
}CTBox;
//树结构
typedef struct
{
CTBox nodes[MAX_TRUE_SIZE]; //结点数组
int r,n; //根的位置和结点数
}CTree
把把双亲表示法和孩子表示法综合一下表示以下这种表示法叫作双亲孩子表示法,应该算是孩子表示法的改进。
孩子兄弟表示法
任一棵树,它的结点的第一个孩子若是存在就是惟一的,它的右兄弟若是存在也是惟一的。所以。咱们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。data是数据域,fitstchild为指针域,存储该结点的第一个孩子结点的存储地址,rightsib是指针域,存储该结点的右兄弟结点的存储位置。
//孩子兄弟表示法结构定义
typedef struct CSDNode
{
TElemType data;
struct CSNode *firstchild,*rightsib;
}CSNode,*CSTree;
这种方法的示意图以下所示这种表示法,给查找某个结点的某个孩子带来了方便,只须要经过firstchild找到此结点的长子,而后在经过长子结点的rightsib找到它的二弟,接着一直找下去,直到找到具体的孩子。
● 面试官 | Java转List三种方式,你说说吧。我。。懵逼。啥时候有三种了
给我个好看再走好吗?
本文分享自微信公众号 - 小明菜市场(fileGeek)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。