//结点结构
class PTNode{
String data;//结点数据
int parent;//双亲位置
}
class PTree{
PTNode[] nodes = new PTnode[size];
int r;//根的位置
int n;//结点个数
}
双亲表示法如图所示:
以上存储结构,根据结点parent指针找到双亲结点的时间复杂度为O(1),parent为-1,表示
找到了树结点的根。结点的孩子需要遍历整个结构。
可以增加结点最左边孩子的域,可以叫长子域,这样可以得到结点的孩子。
可以增加结点右兄弟域来体现兄弟关系。
孩子表示法每个结点有多个指针域,其中每个指针指向一棵子树的根结点。这种方法叫作多重链表表示法。
树的每个结点的度,它的孩子的个数是不同的。所以有两种解决方案:
- 方案一
指针域的个数等于树的度(树的度是各个结点度的最大值)
缺点:树中各个结点度相差很大时,很浪费空间。如果树中结点度相差较少,就意味着开辟的空间被充分利用了。存储结构的缺点就变成了
优点。
- 方案二(按需分配)
专门取一个位置来存储结点指针域的个数(degree)。
该方法空间利用率提高了,但是各个链表是不相同的结构,加上要维护结点的度的数值,运算上会带来损耗。
能否有更好的方法?减少空指针的浪费又能使结点结构相同?
我们为了遍历整棵树,把每个结点放到一个顺序存储结构的数组中,每个结点的孩子有多少是不确定的,所以再对每个结点
的孩子建立一个单链表体现它们的关系。
这就是 合理 的孩子表示法。
每个结点的孩子排列起来,以单链表作存储结构。n个结点有n个孩子链表,如果是叶子结点则此单链表为空。n个头指针又组成
一个线性表,采用顺序存储结构,存放进一个一位数组中。
//孩子结点
class CTNode{
int child;//数组下标
CTNode next;//孩子链表指针域
}
//表头结构
class CTBox{
String data;//数据域
CTNode firstchild;//第一个孩子指针
}
class Tree{
CTBox[] ctBox = new CTBox[size];
int r,n;
}
- 优点:查找某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个结点的孩子单链表即可。遍历整棵树,对头结点数组遍历即可。
- 缺点:如果想知道某个结点的双亲需要遍历整棵树。
可以针对此数据结构的缺点改进为 双亲孩子表示法
孩子兄弟表示法双亲、孩子、兄弟角度研究树的存储结构。
规律:任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此我们可以设置两个指针,分别指向该结点的
第一个孩子和此结点的右兄弟。
clss CSNode{
String data;
CSNode firstchild;
CSNode rightsib;
}
上面的结构查找某个结点的孩子很方便,如何查找双亲?可以增加一个parent指针域来解决查找双亲。
上图变形之后就是一棵二叉树,可以使用二叉树的特性



