package net.shadowfacts.cacao.util import java.util.* import kotlin.NoSuchElementException /** * A linear time algorithm for finding the lowest common ancestor of two nodes in a graph. * Based on https://stackoverflow.com/a/6342546/4731558 * * Works be finding the path from each node back to the root node. * The LCA will then be the node after which the paths diverge. * * @author shadowfacts */ object LowestCommonAncestor { fun find(node1: Node, node2: Node, parent: Node.() -> Node?): Node? { @Suppress("NAME_SHADOWING") var node1: Node? = node1 @Suppress("NAME_SHADOWING") var node2: Node? = node2 val parent1 = LinkedList() while (node1 != null) { parent1.push(node1) node1 = node1.parent() } val parent2 = LinkedList() while (node2 != null) { parent2.push(node2) node2 = node2.parent() } // paths don't converge on the same root element if (parent1.first != parent2.first) { return null } var oldNode: Node? = null while (node1 == node2 && parent1.isNotEmpty() && parent2.isNotEmpty()) { oldNode = node1 node1 = parent1.popOrNull() node2 = parent2.popOrNull() } return if (node1 == node2) node1!! else oldNode!! } } private fun LinkedList.popOrNull(): T? { return try { pop() } catch (e: NoSuchElementException) { null } }