假设目前有这样一个序列:ABCDEFG,这个序列中的节点(如:A,E)可以是任意实体,而这个序列可能以数组,链表的方式存储。将这个序列转换成如下左图所示的逻辑树,需要哪些条件呢?1.遍历方式为先序(或者其他);2.节点间的关系(如节点的子节点)。即这个序列可以表示为:A(B(C),D,E(F,G))。
实际上,条件1完全可以不要:需要遍历方式是要确定根节点(先序)或者叶子节点(后序)。分析可知,没有父亲的节点为根节点(或者没有孩子的节点就是叶子节点)。也就是说,只要有getParent或者getChildren方法,就可以确定各个节点的关系了(节点类型也确定了)。即通过一个序列得到一颗树只需要一个条件:确定节点间关系。
确定节点关系两类算法实现:先找到根节点,然后再依次找到子节点直到叶子节点;先确定各个节点的深度,深度最小的(可以设为0)显然就是根节点,依次得到子节点和叶子节点。
现在假设每个节点都知道自己的孩子节点(即有getChildren方法)。来看看第一种算法如何实现。这里最关键的问题就是如何找到根节点。可以用排除法考虑:某节点的孩子节点一定不是根节点。即遍历所有节点,排除每个节点的孩子节点,最终剩下的就是根节点(可能是多个)。实现如下表所示:
public List<Object> getRoots(List<Object> list) { List<Object> cloneList = new ArrayList<Object>(); cloneList.addAll(list); for(int i=0;i<list.size();i++) { Object o = list.get(i); //子节点不可能成为根节点,所以移除 List<Object> children = getChildren(list, o); if(children != null && children.size() > 0) cloneList.removeAll(children); } //边界 if(list.size() == cloneList.size()) { return cloneList; }else { return getRoots(cloneList); } } |