需要实现一个文件目录树,用于文件的快速查询,因此打算实现一个快速的树形结构。
设计思路是所有树节点均存储在map中,根中保留有子节点的key的Set字段child。因此树也可以根据需要改造成为有序树,可以修改childInit或使用构造器Forest(Supplier extends Set> childInit)即可将默认的HashSet修改为TreeSet。完成有序树。 获得以某节点作为根的树形结构
效率:
因为节点均存储在hashmap中,在1.8的haspMap实现中,主要是依据hash+红黑树,因此构建节点数m,时间复杂度为mlog(m) 构建|移动|删除 时间复杂度为2NO(log(n)),n=节点数,appendChain(ks.length=2); 获取某节点O(log(n)) n=总节点个数.
先根遍历在不考虑栈的情况下,某树下的所有节点 nO(nlog(n)) n=子树节点数
注:
key 的判断主要是需要满足hashmap 对key 的要求,即为hashcode和equals。因此重写这两个方法即可.
首先实现一个基础的树形数据结构。
/**
*
* @author yuyi
* @param
*/
public class Forest implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
protected Supplier extends Set> childInit = () -> new HashSet<>();
private Set roots = childInit.get();
protected HashMap map;
public Tree get(K key) {
return map.get(key);
}
/** 独立某个子树 */
public Tree aloneTree(K k1) {
Tree t = get(k1);
if (t == null)
return null;
if (t.par != null) {
t.parent().child.remove(k1);
t.par = null;
roots.add(k1);
}
return t;
}
/**
* 添加一个有序链
*
*
* 例如添加 1 2 3 则树为{k=1,son=[{k=2,son=[{key=3}]}]}
* 再次添加 1 4 则树为{k=1,son=[{k=2,son=[{key=3}]},{key=4}]}
* 再次添加 2 4 则树为{k=1,son=[{k=2,son=[{key=3},{key=4}]}]}
*
*
* @param ks
* 线性有序子树(即每层仅一个节点)
* @return
*/
@SuppressWarnings("unchecked")
public Forest appendChain(K... ks) {
assert ks != null && ks.length > 2 && ks[0] != null && ks[1] != null;
K k, pk = null;
int i = 0;
Tree curr = map.get(ks[i]), par = curr != null ? curr.parent() : null;
Set f = roots;
if (par != null) {
i = 1;
f = par.child;
}
for (; ks.length > i; i++) {
if (Objects.equals(k = ks[i], pk))
continue;
if ((curr = map.get(pk = k)) == null) {
curr = new Tree(k);
}
if (!f.contains(k)) {
if (par == null || !Objects.equals(curr.par, par)) {
if (curr.par == null)
roots.remove(k);
else
curr.parent().child.remove(k);
curr.par = par != null ? par.key : curr.par;
f.add(k);
map.put(k, curr);
}
}
par = curr;
f = curr.child;
}
return this;
}
public Forest appendChain(Iterator iterator) {
assert iterator != null;
Set f = roots;
Tree curr = null, par = null;
K k, pk = null;
while (iterator.hasNext()) {
if (Objects.equals(k = iterator.next(), pk))
continue;
if ((curr = map.get(k)) == null) {
curr = new Tree(k);
}
if (!f.contains(k)) {
if (par == null || !Objects.equals(curr.par, par)) {
if (curr.par == null)
roots.remove(k);
else
curr.parent().child.remove(k);
curr.par = par != null ? par.key : curr.par;
if (curr.par != null && roots == f) {
f = curr.parent().child;
}
f.add(k);
map.put(k, curr);
}
}
par = curr;
f = curr.child;
}
return this;
}
public void setRoots(Collection trees) {
trees.iterator()