需要实现一个文件目录树,用于文件的快速查询,因此打算实现一个快速的树形结构。
设计思路是所有树节点均存储在map中,根中保留有子节点的key的Set字段child。因此树也可以根据需要改造成为有序树,可以修改childInit或使用构造器Forest(Supplier<? extends Set<K>> 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 <K>
*/
public class Forest<K> implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
protected Supplier<? extends Set<K>> childInit = () -> new HashSet<>();
private Set<K> roots = childInit.get();
protected HashMap<K, Tree> 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;
}
/**
* 添加一个有序链
*
* <pre>
* 例如添加 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}]}]}
* </pre>
*
* @param ks
* 线性有序子树(即每层仅一个节点)
* @return
*/
@SuppressWarnings("unchecked")
public Forest<K> 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<K> 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<K> appendChain(Iterator<K> iterator) {
assert iterator != null;
Set<K> 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<Tree> trees) {
trees.iterator().forEachRemaining(this::append);
}
public Forest<K> merge(Forest<K> forest) {
setRoots(forest.getRoots());
return this;
}
public Forest<K> append(Forest<K>.Tree tree) {
assert tree != null;
K k;
Tree curr, p;
if ((p = map.get(k = tree.par)) == null)
tree.par = null;
else
p.child.add(tree.key);
Iterator<Tree> it = tree.toFirstRootList();
while (it.hasNext()) {
curr = it.next();
if ((p = map.get(k = curr.key)) == null) {
map.put(k, p = new Tree(k));
}
p.par = curr.par;
p.child.addAll(curr.child);
}
return this;
}
public Collection<Tree> getRoots() {
return roots.stream().map(t -> map.get(t)).collect(Collectors.toList());
}
public int getAloneTreeSize() {
return roots.size();
}
public boolean containsKey(K key) {
return map.containsKey(key);
}
public Forest<K> remove(K key) {
Tree t = map.get(key);
if (t == null)
return this;
if (t.par == null) {
roots.remove(t.key);
} else {
t.parent().child.remove(t.key);
}
Iterator<Tree> it = t.toFirstRootList();
while (it.hasNext()) {
map.remove(it.next());
}
return this;
}
public static void main(String[] args) {
Forest<String> tree = new Forest<>();
tree.appendChain("1", "2", "3", "4");
tree.appendChain("1", "1", "5", "6");
tree.appendChain("7", "8");
tree.appendChain("1", "7", "8", "9");
tree.appendChain("1", "8");
tree.appendChain("1", "8", "7", "6");
System.out.println(tree);
System.out.println(JSONObject.toJSONString(tree.getRoots()));
System.out.println(JSONObject.toJSONString(tree));
// System.out.println("--------------------------");
// System.out.println("toFirstRootList");
// tree.get("1").toFirstRootList().forEachRemaining(k -> System.out.println(k));
// System.out.println("toLevelRootList");
// tree.get("1").toLevelRootList().forEachRemaining(k -> System.out.println(k));
// System.out.println("toLeafNodeList");
// tree.get("1").toLeafNodeList().forEachRemaining(k -> System.out.println(k));
// System.out.println("toTreeNodeList");
// tree.get("1").toTreeNodeList().forEachRemaining(k -> System.out.println(k));
// System.out.println("toLevelList 2");
// tree.get("1").toLevelList(2).forEachRemaining(k -> System.out.println(k));
// System.out.println("toLevelList 1");
// tree.get("1").toLevelList(1).forEachRemaining(k -> System.out.println(k));
// System.out.println("toLevelList 0");
// tree.get("1").toLevelList(0).forEachRemaining(k -> System.out.println(k));
// System.out.println("toLevelList 3");
// tree.get("1").toLevelList(3).forEachRemaining(k -> System.out.println(k));
// System.out.println("toParentNodeList");
// tree.get("6").toParentNodeList().forEachRemaining(k ->
// System.out.println(k));
tree.append("1", (str) -> (Integer.valueOf(str) - 1 < 0 ? "0" : "" + (Integer.valueOf(str) - 1)));
tree.append("0", (str) -> (Integer.valueOf(str) - 1 < 0 ? "0" : "" + (Integer.valueOf(str) - 1)));
tree.append((str) -> (Integer.valueOf(str) - 1 < 0 ? "0" : "" + (Integer.valueOf(str) - 1)), "10", "11", "12",
"13", "14");
System.out.println(tree);
}
/**
* 树形节点
*
* @author yuyi
*/
public class Tree implements Serializable {
/**
* 先根遍历所有树根节点
*
* @author yuyi
*/
class FirstRootTreeNodeIterator extends FirstRootIterator {
protected void get() {
getflag = true;
do {
curr = null;
if (sons == null)
return;
if (!sons.hasNext()) {
do {
if (soniterators.isEmpty())
return;
sons = soniterators.pop();
} while (!sons.hasNext());
}
c = sons.next();
curr = map.get(c);
soniterators.push(sons);
sons = curr.child.iterator();
} while (!sons.hasNext());
}
}
/**
* 先根遍历叶子节点
*
* @author yuyi
*/
class FirstRootLeftNodeIterator extends FirstRootIterator {
FirstRootLeftNodeIterator() {
curr = null;
getflag = false;
}
protected void get() {
getflag = true;
do {
if (sons == null)
return;
if (!sons.hasNext()) {
do {
if (soniterators.isEmpty())
return;
sons = soniterators.pop();
} while (!sons.hasNext());
}
c = sons.next();
curr = map.get(c);
soniterators.push(sons);
sons = curr.child.iterator();
} while (sons.hasNext());
}
}
/**
* 先根遍历
*
* @author yuyi
*/
class FirstRootIterator implements Iterator<Tree> {
protected Tree root = Tree.this, curr = root, por = root;
protected K c;
protected Iterator<K> sons = Tree.this.child.iterator();
protected boolean getflag = true;
protected Stack<Iterator<K>> soniterators = new Stack<>();
@Override
public boolean hasNext() {
if (curr == null && !getflag) {
get();
}
return curr != null;
}
protected void get() {
getflag = true;
if (sons == null)
return;
if (!sons.hasNext()) {
do {
if (soniterators.isEmpty())
return;
sons = soniterators.pop();
} while (!sons.hasNext());
}
c = sons.next();
curr = map.get(c);
soniterators.push(sons);
sons = curr.child.iterator();
}
@Override
public Tree next() {
if (curr == null && !getflag) {
get();
}
getflag = false;
por = curr;
curr = null;
return por;
}
}
/**
* 水平遍历
* <p>
* 逐层读取
* </p>
*
* @author yuyi
*/
class LevelRootIterator extends FirstRootIterator {
protected Queue<Iterator<K>> soniterators = new LinkedList<>();
protected void get() {
getflag = true;
if (sons == null)
return;
if (!sons.hasNext()) {
do {
if (soniterators.isEmpty())
return;
sons = soniterators.poll();
} while (!sons.hasNext());
}
c = sons.next();
curr = map.get(c);
soniterators.add(curr.child.iterator());
}
}
/**
* 读取指定层节点
*
* @author yuyi
*/
class LevelNodeIterator extends LevelRootIterator {
@SuppressWarnings("unchecked")
protected Queue<Iterator<K>>[] soniteratorss = new Queue[] { new LinkedList<>(), new LinkedList<>() };
protected int level;
protected int currlevel = 0;
protected int parindex = 0;
LevelNodeIterator(int level) {
this.level = level;
if (level > currlevel) {
curr = null;
getflag = false;
soniteratorss[parindex].add(sons);
sons = null;
}
currlevel = 1;
}
protected void get() {
getflag = true;
if (level < currlevel)
return;
do {
curr = null;
while (sons == null || !sons.hasNext()) {
if ((soniterators = soniteratorss[parindex]).isEmpty()) {
if (level <= currlevel)
return;
soniterators = soniteratorss[parindex = 1 - parindex];
currlevel++;
}
sons = soniterators.poll();
}
curr = map.get(sons.next());
soniteratorss[1 - parindex].add(curr.child.iterator());
} while (currlevel != level);
}
}
/**
* 获取指定节点的父节点
*
* @author yuyi
*/
class ParentNodeIterator implements Iterator<Tree> {
Tree curr = Tree.this;
@Override
public boolean hasNext() {
return curr != null;
}
@Override
public Forest<K>.Tree next() {
Tree t = curr;
curr = curr.par != null ? map.get(curr.par) : null;
return t;
}
}
public Iterator<Tree> toFirstRootList() {
return new FirstRootIterator();
}
public Iterator<Tree> toLevelRootList() {
return new LevelRootIterator();
}
public Iterator<Tree> toLevelList(int level) {
return new LevelNodeIterator(level);
}
public Iterator<Tree> toParentNodeList() {
return new ParentNodeIterator();
}
public Iterator<Tree> toTreeNodeList() {
return new FirstRootTreeNodeIterator();
}
public Iterator<Tree> toLeafNodeList() {
return new FirstRootLeftNodeIterator();
}
private static final long serialVersionUID = 1L;
protected K key;
protected K par;
protected final Set<K> child;
public K getKey() {
return key;
}
public Tree parent() {
return par == null ? null : map.get(par);
}
public List<Tree> getChilds() {
return child.stream().map(map::get).collect(Collectors.toList());
}
public Tree(K key) {
this.key = key;
this.child = childInit.get();
}
@Override
public String toString() {
return String.format("{key=" + key + "%s}", child.isEmpty() ? "" : ",childs=" + getChilds());
}
}
public int size() {
return map.size();
}
public boolean empty() {
return map.isEmpty();
}
public void clear() {
map.clear();
}
public Forest() {
map = new HashMap<>();
}
public Forest(Supplier<? extends Set<K>> childInit) {
this.childInit = childInit;
}
@Override
public String toString() {
return StringUtils.join(roots.stream().map(t -> map.get(t).toString()).iterator(), ",");
}
/**
* 无序添加
*
*
* @param ks
* @param getParent
* @return
*/
public Forest<K> append(K k, Function<K, K> getParent) {
if (k == null)
return this;
Tree curr = null, par = null, oldpar;
K pk;
if ((curr = map.get(k)) == null) {
curr = new Tree(k);
}
map.put(k, curr);
while ((pk = getParent.apply(k)) != null && !Objects.equals(pk, k)) {
par = map.get(pk);
if ((oldpar = curr.parent()) != null)
oldpar.child.remove(k);
else
roots.remove(k);
if (par != null) {
par.child.add(k);
return this;
}
par = new Tree(pk);
par.child.add(k);
curr.par = pk;
curr = par;
k = pk;
map.put(k, par);
}
roots.add(k);
return this;
}
/**
* 无序列表添加
*
* @param ks
* @param getParent
* @return
*/
@SuppressWarnings("unchecked")
public Forest<K> append(Function<K, K> getParent, K k, K... ks) {
assert getParent != null;
append(k, getParent);
Stream.of(ks).forEach(t -> append(t, getParent));
return this;
}
/**
* 无序列表添加
*
* @param ks
* @param getParent
* @return
*/
public Forest<K> append(Collection<K> list, Function<K, K> getParent) {
assert list != null;
list.forEach(t -> append(t, getParent));
return this;
}
/**
*
* @param ks
* @param getParent
* @return
*/
public Forest<K> append(Iterator<K> iterator, Function<K, K> getParent) {
assert iterator != null;
while (iterator.hasNext()) {
append(iterator.next(), getParent);
}
return this;
}
}
这个基础树,可以支持有根树的自动构造,只要插值满足值需要为(根节点,子根节点,三级根节点...叶子节点)即可。并提供了基础的子树遍历方法:先根遍历。逐层遍历等。
然后就可以在这个的基础上实现一个文件目录树
/**
* 文件目录树
*
* @author yuyi
*/
public class PathTree extends Forest<PathTree.FileNode> {
private static final long serialVersionUID = 1L;
public static class FileNode {
FileNode(Path p) {
this.path = p;
filename = p.getFileName() == null ? p.toString() : p.getFileName().toString();
}
String filename;
Path path;
boolean isDirectory;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public Path getPath() {
return path;
}
public void setPath(Path path) {
this.path = path;
}
@Override
public String toString() {
return path.toString();
}
@Override
public int hashCode() {
return path == null ? 0 : path.hashCode();
}
@Override
public boolean equals(Object obj) {
return this == obj || obj != null && hashCode() == obj.hashCode();
}
}
public class PathTreeVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
appendChain(new FileNode(file.getParent()), new FileNode(file));
return super.visitFile(file, attrs);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
appendChain(new FileNode(dir.getParent()), new FileNode(dir));
return super.postVisitDirectory(dir, exc);
}
}
public void append(Path p) {
Path p1;
while ((p1 = p.getParent()) != null) {
appendChain(new FileNode(p1), new FileNode(p));
p = p1;
}
}
/**
* 读取某个文件目录下的所有文件并将其组织为树形结构存储
*
* @throws IOException
*/
public void read(Path path) {
assert Files.exists(path);
if (!Files.isDirectory(path))
throw new IllegalArgumentException(" path not`s Directory! ");
append(path);
try {
Files.walkFileTree(path, new PathTreeVisitor());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
PathTree pathtree = new PathTree();
pathtree.read(Paths.get("G:\\war3\\Warcraft3\\Maps"));
System.out.println(JSONObject.toJSONString(pathtree));
System.out.println(pathtree);
// pathtree.getRoots().forEach(p ->
// p.toFirstRootList().forEachRemaining(System.out::println));
}
}