package com.sap.ide.cts.parser.incremental.util; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Used to find the least common ancestor in two given nodes within a tree. This is an implementation of <a * href="http://en.wikipedia.org/wiki/Tarjan%27s_off-line_least_common_ancestors_algorithm">Tarjan's off-line least common * ancestor algorithm</a> which has a linear complexity! */ public class TarjansLCA<T> { private ITarjanTreeContentProvider<T> contentProvider; public TarjansLCA(ITarjanTreeContentProvider<T> provider) { if (provider == null) { contentProvider = new DefaultTarjanTreeContentProvider<T>(); } else { contentProvider = provider; } } public T lcaSearch(T rootNode, T from, T to) { SearchSet<T> query = new SearchSet<T>(from, to); lca(new Node<T>(rootNode), Collections.singletonList(query)); return query.result; } public void lca(Node<T> node, List<SearchSet<T>> queries) { MakeSet(node); // u.ancestor = u; for (Node<T> subnode : contentProvider.getChildren(node)) { lca(subnode, queries); union(node, subnode); find(node).ancestor = node; } node.checked = true; for (SearchSet<T> query : queries) { if (query.start.equals(query.end)) { query.result = query.start; } if (query.start.equals(node.argumet)) { query.startNode = node; if ((query.endNode != null && query.endNode.checked)) { query.result = find(query.endNode).argumet; } } else if (query.end.equals(node.argumet)) { query.endNode = node; if (query.startNode != null && query.startNode.checked) { query.result = find(query.startNode).argumet; } } } } private Node<T> find(Node<T> node) { Node<T> n = node; for (; n.ancestor != n; n = n.ancestor) { ; } return n; } private void union(Node<T> node1, Node<T> node2) { node2.ancestor = node1; } private void MakeSet(Node<T> u) { u.ancestor = u; } public static class SearchSet<T> { public T result; public T end; public Node<T> endNode; public T start; public Node<T> startNode; public SearchSet(T start, T end) { super(); this.start = start; this.end = end; } } public static class Node<T> { private T argumet; public Node(T arg, Node<T> parent) { this.argumet = arg; if (parent != null) { parent.children.add(this); } } public Node(T argument) { argumet = argument; } public List<Node<T>> children = new ArrayList<Node<T>>(); public boolean checked = false; public Node<T> ancestor; public T getArgumet() { return argumet; } public void setArgumet(T argumet) { this.argumet = argumet; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((argumet == null) ? 0 : argumet.hashCode()); return result; } @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Node<T> other = (Node<T>) obj; if (argumet == null) { if (other.argumet != null) { return false; } } else if (!argumet.equals(other.argumet)) { return false; } return true; } } }