diff --git a/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.java b/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.java deleted file mode 100644 index 167352ba..00000000 --- a/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.java +++ /dev/null @@ -1,170 +0,0 @@ -package dev.openrs2.util.collect; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Queue; - -public final class ForestDisjointSet implements DisjointSet { - private static final class Node implements Partition { - private final List> children = new ArrayList<>(); - private final T value; - private Node parent = this; - private int rank = 0; - - private Node(T value) { - this.value = value; - } - - private void setParent(Node parent) { - this.parent = parent; - this.parent.children.add(this); - } - - private Node find() { - if (parent != this) { - parent = parent.find(); - } - return parent; - } - - @Override - public Iterator iterator() { - return new NodeIterator<>(find()); - } - - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object other) { - if (other == null || getClass() != other.getClass()) { - return false; - } - - var node = (Node) other; - return find() == node.find(); - } - - @Override - public int hashCode() { - return find().value.hashCode(); - } - - @Override - public String toString() { - return find().value.toString(); - } - } - - private static class NodeIterator implements Iterator { - private final Queue> queue = new ArrayDeque<>(); - - public NodeIterator(Node root) { - this.queue.add(root); - } - - @Override - public boolean hasNext() { - return !queue.isEmpty(); - } - - @Override - public T next() { - var node = queue.poll(); - if (node == null) { - throw new NoSuchElementException(); - } - - queue.addAll(node.children); - return node.value; - } - } - - private static class SetIterator implements Iterator> { - private final Iterator> it; - - public SetIterator(ForestDisjointSet set) { - this.it = new HashSet<>(set.nodes.values()).iterator(); - } - - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public Partition next() { - return it.next(); - } - } - - private final Map> nodes = new HashMap<>(); - private int elements = 0, partitions = 0; - - @Override - public Partition add(T x) { - var node = nodes.get(x); - if (node != null) { - return node.find(); - } - - elements++; - partitions++; - - nodes.put(x, node = new Node<>(x)); - return node; - } - - @Override - public Partition get(T x) { - return get0(x); - } - - private Node get0(T x) { - var node = nodes.get(x); - if (node == null) { - return null; - } - return node.find(); - } - - @Override - public void union(Partition x, Partition y) { - var xRoot = ((Node) x).find(); - var yRoot = ((Node) y).find(); - - if (xRoot == yRoot) { - return; - } - - if (xRoot.rank < yRoot.rank) { - xRoot.setParent(yRoot); - } else if (xRoot.rank > yRoot.rank) { - yRoot.setParent(xRoot); - } else { - yRoot.setParent(xRoot); - xRoot.rank++; - } - - partitions--; - } - - @Override - public int getElements() { - return elements; - } - - @Override - public int getPartitions() { - return partitions; - } - - @Override - public Iterator> iterator() { - return new SetIterator<>(this); - } -} diff --git a/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.kt b/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.kt new file mode 100644 index 00000000..b5dd912b --- /dev/null +++ b/util/src/main/java/dev/openrs2/util/collect/ForestDisjointSet.kt @@ -0,0 +1,117 @@ +package dev.openrs2.util.collect + +import java.util.* +import kotlin.NoSuchElementException + +class ForestDisjointSet : DisjointSet { + private class Node(val value: T) : DisjointSet.Partition { + val children = mutableListOf>() + private var _parent = this + var parent + get() = _parent + set(parent) { + _parent = parent + _parent.children.add(this) + } + var rank = 0 + + fun find(): Node { + if (parent !== this) { + _parent = parent.find() + } + return parent + } + + override fun iterator(): Iterator { + return NodeIterator(find()) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Node<*>) return false + + return find() === other.find() + } + + override fun hashCode(): Int { + return find().value.hashCode() + } + + override fun toString(): String { + return find().value.toString() + } + } + + private class NodeIterator(root: Node) : Iterator { + private val queue = ArrayDeque>() + + init { + queue.add(root) + } + + override fun hasNext(): Boolean { + return queue.isNotEmpty() + } + + override fun next(): T { + val node = queue.poll() ?: throw NoSuchElementException() + queue.addAll(node.children) + return node.value + } + } + + private val nodes = mutableMapOf>() + override val elements + get() = nodes.size + override var partitions = 0 + private set + + override fun add(x: T): DisjointSet.Partition { + val node = findNode(x) + if (node != null) { + return node + } + + partitions++ + + val newNode = Node(x) + nodes[x] = newNode + return newNode + } + + override fun get(x: T): DisjointSet.Partition? { + return findNode(x) + } + + private fun findNode(x: T): Node? { + val node = nodes[x] ?: return null + return node.find() + } + + override fun union(x: DisjointSet.Partition, y: DisjointSet.Partition) { + require(x is Node) + require(y is Node) + + val xRoot = x.find() + val yRoot = y.find() + + if (xRoot == yRoot) { + return + } + + if (xRoot.rank < yRoot.rank) { + xRoot.parent = yRoot + } else if (xRoot.rank > yRoot.rank) { + yRoot.parent = xRoot + } else { + yRoot.parent = xRoot + xRoot.rank++ + } + + partitions-- + } + + override fun iterator(): Iterator> { + return nodes.values.iterator() + } +}