1:从一棵普通的树开始!
现在,如果你去谷歌树的实现,他们会教你这样定义:
public class Tree <T> {
private T item;
private Tree left;
private Tree right;
.......
}
然后得到如下的示例图
But, Fck it! It's a tree too !!!!
一开始灌输二叉树的概念(最多只有2个子节点),或许是件好事,不过我喜欢从最愚蠢的方式开始,这样可以更加透彻的了解什么是树!
所以,这是我对一棵普通的树的定义:
public class NormalTree <T> {
private NormalTree<T> parent;
private T item;
private List<NormalTree<T>> descendant ;
public NormalTree(NormalTree<T> parent,T item, List<NormalTree<T>> descendant) {
this.parent = parent;
this.item = item;
this.descendant = Objects.requireNonNullElseGet(descendant, () -> new ArrayList<>(1));
}
public NormalTree() {
this.parent = null;
this.item = null;
this.descendant = new ArrayList<>(1);
}
public NormalTree<T> getParent() {
return parent;
}
public void setParent(NormalTree<T> parent) {
this.parent = parent;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
public List<NormalTree<T>> getDescendant() {
return descendant;
}
public void setDescendant(List<NormalTree<T>> descendant) {
this.descendant = descendant;
}
}
有了树的定义,就可以种一棵和图二一样的树了:
public class TreeLauncher {
public static void main(String[] args) {
//从ROOT节点开始
NormalTree<Integer> normalTree = new NormalTree<>(null,1,null);
//让我们为root节点添加子节点
List<NormalTree<Integer>> descendantOfRoot = new ArrayList<>();
normalTree.setDescendant(descendantOfRoot);
NormalTree<Integer> descendant1 = new NormalTree<>();
descendant1.setItem(2);
descendant1.setParent(normalTree);
NormalTree<Integer> descendant2 = new NormalTree<>();
descendant2.setItem(4);
descendant2.setParent(normalTree);
descendantOfRoot.add(descendant1);
descendantOfRoot.add(descendant2);
//此时root节点的儿子节点,都创建好了,但是还没完,儿子还有儿子呢!!!
NormalTree<Integer> descendant1OfItem2 = new NormalTree<>();
descendant1OfItem2.setItem(5);
descendant1OfItem2.setParent(descendant1);
NormalTree<Integer> descendant2OfItem2 = new NormalTree<>();
descendant2OfItem2.setItem(6);
descendant2OfItem2.setParent(descendant1);
NormalTree<Integer> descendant3OfItem2 = new NormalTree<>();
descendant3OfItem2.setItem(7);
descendant3OfItem2.setParent(descendant1);
descendant2.getDescendant().add(descendant1OfItem2);
descendant2.getDescendant().add(descendant2OfItem2);
descendant2.getDescendant().add(descendant3OfItem2);
//Assert == 6
System.out.println(normalTree.getDescendant().get(1).getDescendant().get(1).getItem());
}
}
2:树的重要属性有哪些?
-
leave —— 叶节点:没有子节点的节点,就是叶子节点
-
edge —— 边:边就是两个节点之间的那条直线了。N个元素的树,edge = N-1
-
degree —— 度:即节点的子节点数,其中最大的那个,就是树的度!
-
depth —— 节点的深度、树的深度:从root开始数,而且是从1开始(程序员的惯性从0开始),到目标节点经过的节点数,就是节点的深度。而树的深度,则是root到叶子节点经过的节点数的最大值。
-
height —— 节点的高度、树的高度:深度是从root往下数,高度则是从叶子从下往上数,也是从1开始。
以图二举个例子:
- Leave有4个,分别是5,6,7,4。因为他们都没有子节点了。
- edge有5条。
- root节点1的degree是2,因为root只有2和4两个子节点,5,6,7是儿子的孙子节点,不算!
- 2节点的degree是3,因为它有5,6,7三个儿子节点。
- 4的degree是0,因为它没有儿子节点。
- 整棵树的degree是3,因为degree的最大值就是3。
- root节点1的depth是1。
- 值为6的节点的depth是3。
- 整棵树的depth是3。
- root节点1的height是3,因为从最远的叶节点5,6,7往上到1,经过的最大节点数是3。
- 4的高度是1。
- 2的高度是2。
- 整棵树的高度是3。
3:森林的概念!
森林是由一棵棵不相交的树组成的。那么问题来了,下面两棵树,是森林么?
当然不是,因为这两棵树,可以通过数值2连通起来。
这像不像是我们在之前提到的并查集概念?简直就是一样好么!!!!!
所以,如果要合并两棵树,你现在应该知道怎么做了吧?
4:What's next ?
好吧,说完了这种普通的树,下一篇,我们正式开始谈谈二叉树!
BTW,你们有没有发现树目前最大的缺点?
没错,就是太吉尔占内存了!不过万幸的是,对于应用层来说,内存如今并不值钱!