基于java的树形数据结构实现

本文介绍了一种基于Java的高效文件目录树实现方法,利用HashMap存储树节点,通过递归构建和遍历实现文件的快速查询。文章详细阐述了树形结构的设计思路,包括节点的添加、移动、删除以及子树的遍历算法,并展示了如何应用于文件目录的组织。

需要实现一个文件目录树,用于文件的快速查询,因此打算实现一个快速的树形结构。

设计思路是所有树节点均存储在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));

	}

}

转载于:https://my.oschina.net/yuyizyk/blog/1924573

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值