summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/funcutils/TreeUtils.java
blob: 8392f1c85f2c2898f539c2cf3507973102899581 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package bjc.utils.funcutils;

import java.util.LinkedList;
import java.util.function.Predicate;

import bjc.data.ITree;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;

/**
 * Implements various utilities for trees.
 *
 * @author Benjamin Culkin
 */
public class TreeUtils {
	/**
	 * Convert a tree into a list of outline nodes that match a certain
	 * path.
	 * 
	 * @param tre
	 *        The tree to outline.
	 * @param leafMarker
	 *        The path to mark nodes with.
	 * @return The list of marked paths.
	 */
	public static <T> IList<IList<T>> outlineTree(ITree<T> tre, Predicate<T> leafMarker) {
		IList<IList<T>> paths = new FunctionalList<>();

		LinkedList<T> path = new LinkedList<>();
		path.add(tre.getHead());

		tre.doForChildren((child) -> findPath(child, path, leafMarker, paths));

		return paths;
	}

	/* Find a path in a tree. */
	private static <T> void findPath(ITree<T> subtree, LinkedList<T> path, Predicate<T> leafMarker,
			IList<IList<T>> paths) {
		if(subtree.getChildrenCount() == 0 && leafMarker.test(subtree.getHead())) {
			/* We're at a matching leaf node. Add it. */
			IList<T> finalPath = new FunctionalList<>();

			for(T ePath : path) {
				finalPath.add(ePath);
			}

			finalPath.add(subtree.getHead());

			paths.add(finalPath);
		} else {
			/* Check the children of this node. */
			path.add(subtree.getHead());

			subtree.doForChildren((child) -> findPath(child, path, leafMarker, paths));

			path.removeLast();
		}
	}
}