io.vavr.collection.PriorityQueue Maven / Gradle / Ivy
Show all versions of vavr Show documentation
/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/
*
* Copyright 2014-2019 Vavr, http://vavr.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.vavr.collection;
import io.vavr.*;
import io.vavr.collection.PriorityQueueBase.*;
import java.io.Serializable;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import static io.vavr.collection.PriorityQueueBase.*;
/**
* A PriorityQueue.
*
* @author Pap Lőrinc
*/
public final class PriorityQueue extends io.vavr.collection.AbstractQueue> implements Serializable, Ordered {
private static final long serialVersionUID = 1L;
private final Comparator super T> comparator;
private final Seq> forest;
private final int size;
private PriorityQueue(Comparator super T> comparator, Seq> forest, int size) {
this.comparator = comparator;
this.forest = forest;
this.size = size;
}
private PriorityQueue with(Seq> forest, int size) {
return new PriorityQueue<>(comparator, forest, size);
}
@Override
public PriorityQueue collect(PartialFunction super T, ? extends R> partialFunction) {
return ofAll(Comparators.naturalComparator(), iterator(). collect(partialFunction));
}
/**
* Enqueues a new element.
*
* @param element The new element
* @return a new {@code PriorityQueue} instance, containing the new element
*/
@Override
public PriorityQueue enqueue(T element) {
final Seq> result = insert(comparator, element, forest);
return with(result, size + 1);
}
/**
* Enqueues the given elements. A queue has FIFO order, i.e. the first of the given elements is
* the first which will be retrieved.
*
* @param elements An {@link PriorityQueue} of elements, may be empty
* @return a new {@link PriorityQueue} instance, containing the new elements
* @throws NullPointerException if elements is null
*/
@Override
public PriorityQueue enqueueAll(Iterable extends T> elements) {
return merge(ofAll(comparator, elements));
}
/**
* Returns the first element of a non-empty {@link PriorityQueue}.
*
* @return The first element of this {@link PriorityQueue}.
* @throws NoSuchElementException if this is empty
*/
@Override
public T head() {
if (isEmpty()) {
throw new NoSuchElementException("head of empty " + stringPrefix());
} else {
return findMin(comparator, forest).root;
}
}
/**
* Drops the first element of a non-empty {@link PriorityQueue}.
*
* @return A new instance of PriorityQueue containing all elements except the first.
* @throws UnsupportedOperationException if this is empty
*/
@Override
public PriorityQueue tail() {
if (isEmpty()) {
throw new UnsupportedOperationException("tail of empty " + stringPrefix());
} else {
return dequeue()._2;
}
}
@Override
public Tuple2> dequeue() {
if (isEmpty()) {
throw new NoSuchElementException("dequeue of empty " + stringPrefix());
} else {
final Tuple2>> dequeue = deleteMin(comparator, this.forest);
return Tuple.of(dequeue._1, with(dequeue._2, this.size - 1));
}
}
public PriorityQueue merge(PriorityQueue target) {
final Seq> meld = meld(comparator, this.forest, target.forest);
return with(meld, this.size + target.size);
}
/**
* A {@code PriorityQueue} is computed synchronously.
*
* @return false
*/
@Override
public boolean isAsync() {
return false;
}
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* A {@code PriorityQueue} is computed eagerly.
*
* @return false
*/
@Override
public boolean isLazy() {
return false;
}
@Override
public boolean isOrdered() {
return true;
}
/**
* Returns the empty PriorityQueue.
*
* @param Component type
* @return The empty PriorityQueue.
*/
public static > PriorityQueue empty() {
return empty(Comparators.naturalComparator());
}
public static PriorityQueue empty(Comparator super T> comparator) {
return new PriorityQueue<>(comparator, io.vavr.collection.List.empty(), 0);
}
/**
* Returns a {@link Collector} which may be used in conjunction with
* {@link java.util.stream.Stream#collect(Collector)} to obtain a {@code PriorityQueue}.
*
* @param Component type of the {@code PriorityQueue}.
* @return A {@code PriorityQueue} Collector.
*/
public static Collector, PriorityQueue> collector() {
final Supplier> supplier = ArrayList::new;
final BiConsumer, T> accumulator = ArrayList::add;
final BinaryOperator> combiner = (left, right) -> {
left.addAll(right);
return left;
};
final Function, PriorityQueue> finisher = values -> ofAll(Comparators.naturalComparator(), values);
return Collector.of(supplier, accumulator, combiner, finisher);
}
/**
* Narrows a widened {@code PriorityQueue extends T>} to {@code PriorityQueue}
* by performing a type-safe cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param queue An {@code PriorityQueue}.
* @param Component type of the {@code PriorityQueue}.
* @return the given {@code PriorityQueue} instance as narrowed type {@code PriorityQueue}.
*/
@SuppressWarnings("unchecked")
public static PriorityQueue narrow(PriorityQueue extends T> queue) {
return (PriorityQueue) queue;
}
public static > PriorityQueue of(T element) {
return of(Comparators.naturalComparator(), element);
}
@SuppressWarnings("unchecked")
public static > PriorityQueue of(T... elements) {
return ofAll(Comparators.naturalComparator(), io.vavr.collection.List.of(elements));
}
public static PriorityQueue of(Comparator super T> comparator, T element) {
return ofAll(comparator, io.vavr.collection.List.of(element));
}
@SuppressWarnings("unchecked")
public static PriorityQueue of(Comparator super T> comparator, T... elements) {
return ofAll(comparator, io.vavr.collection.List.of(elements));
}
public static > PriorityQueue ofAll(Iterable extends T> elements) {
return ofAll(Comparators.naturalComparator(), elements);
}
@SuppressWarnings("unchecked")
public static PriorityQueue ofAll(Comparator super T> comparator, Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (elements instanceof PriorityQueue && ((PriorityQueue) elements).comparator == comparator) {
return (PriorityQueue) elements;
} else {
int size = 0;
Seq> forest = io.vavr.collection.List.empty();
for (T value : elements) {
forest = insert(comparator, value, forest);
size++;
}
return new PriorityQueue<>(comparator, forest, size);
}
}
public static > PriorityQueue ofAll(java.util.stream.Stream extends T> javaStream) {
return ofAll(Comparators.naturalComparator(), io.vavr.collection.Iterator.ofAll(javaStream.iterator()));
}
public static PriorityQueue ofAll(Comparator super T> comparator, java.util.stream.Stream extends T> javaStream) {
return ofAll(comparator, io.vavr.collection.Iterator.ofAll(javaStream.iterator()));
}
/**
* Returns a {@link PriorityQueue} containing {@code size} values of a given Function {@code function}
* over a range of integer values from {@code 0} to {@code size - 1}.
*
* @param Component type of the {@link PriorityQueue}
* @param size The number of elements in the {@link PriorityQueue}
* @param function The Function computing element values
* @return A {@link PriorityQueue} consisting of elements {@code function(0),function(1), ..., function(size - 1)}
* @throws NullPointerException if {@code function} is null
*/
@GwtIncompatible
public static PriorityQueue tabulate(int size, Function super Integer, ? extends T> function) {
Objects.requireNonNull(function, "function is null");
final Comparator super T> comparator = Comparators.naturalComparator();
return io.vavr.collection.Collections.tabulate(size, function, empty(comparator), values -> ofAll(comparator, io.vavr.collection.List.of(values)));
}
/**
* Returns a {@link PriorityQueue} containing {@code size} values supplied by a given Supplier {@code supplier}.
*
* @param Component type of the {@link PriorityQueue}
* @param size The number of elements in the {@link PriorityQueue}
* @param supplier The Supplier computing element values
* @return A {@link PriorityQueue} of size {@code size}, where each element contains the result supplied by {@code supplier}.
* @throws NullPointerException if {@code supplier} is null
*/
@GwtIncompatible
@SuppressWarnings("unchecked")
public static PriorityQueue fill(int size, Supplier extends T> supplier) {
Objects.requireNonNull(supplier, "supplier is null");
final Comparator super T> comparator = Comparators.naturalComparator();
return io.vavr.collection.Collections.fill(size, supplier, empty(comparator), values -> ofAll(comparator, io.vavr.collection.List.of(values)));
}
/**
* Returns a {@link PriorityQueue} containing {@code n} times the given {@code element}
*
* @param Component type of the {@link PriorityQueue}
* @param size The number of elements in the {@link PriorityQueue}
* @param element The element
* @return A {@link PriorityQueue} of size {@code size}, where each element is the given {@code element}.
*/
@GwtIncompatible
@SuppressWarnings("unchecked")
public static PriorityQueue fill(int size, T element) {
final Comparator super T> comparator = Comparators.naturalComparator();
return io.vavr.collection.Collections.fillObject(size, element, empty(comparator), values -> ofAll(comparator, io.vavr.collection.List.of(values)));
}
@Override
public io.vavr.collection.List toList() {
io.vavr.collection.List results = io.vavr.collection.List.empty();
for (PriorityQueue queue = this; !queue.isEmpty(); ) {
final Tuple2> dequeue = queue.dequeue();
results = results.prepend(dequeue._1);
queue = dequeue._2;
}
return results.reverse();
}
@Override
public PriorityQueue distinct() {
return distinctBy(comparator);
}
@Override
public PriorityQueue distinctBy(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
return isEmpty() ? this : ofAll(comparator, iterator().distinctBy(comparator));
}
@Override
public PriorityQueue distinctBy(Function super T, ? extends U> keyExtractor) {
Objects.requireNonNull(keyExtractor, "keyExtractor is null");
return isEmpty() ? this : ofAll(comparator, iterator().distinctBy(keyExtractor));
}
@Override
public PriorityQueue drop(int n) {
if (n <= 0 || isEmpty()) {
return this;
} else if (n >= length()) {
return empty(comparator);
} else {
return ofAll(comparator, iterator().drop(n));
}
}
@Override
public PriorityQueue dropRight(int n) {
if (n <= 0 || isEmpty()) {
return this;
} else if (n >= length()) {
return empty(comparator);
} else {
return ofAll(comparator, iterator().dropRight(n));
}
}
@Override
public PriorityQueue dropWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
PriorityQueue result = this;
while (!result.isEmpty() && predicate.test(result.head())) {
result = result.tail();
}
return result;
}
@Override
public PriorityQueue filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
if (isEmpty()) {
return this;
} else {
return ofAll(comparator, iterator().filter(predicate));
}
}
@Override
public PriorityQueue flatMap(Function super T, ? extends Iterable extends U>> mapper) {
return flatMap(Comparators.naturalComparator(), mapper);
}
public PriorityQueue flatMap(Comparator comparator, Function super T, ? extends Iterable extends U>> mapper) {
Objects.requireNonNull(comparator, "comparator is null");
Objects.requireNonNull(mapper, "mapper is null");
return ofAll(comparator, iterator().flatMap(mapper));
}
/**
* Accumulates the elements of this {@link PriorityQueue} by successively calling the given function {@code f} from the right,
* starting with a value {@code zero} of type B.
*
* Example: {@code PriorityQueue.of("a", "b", "c").foldRight("", (x, xs) -> x + xs) = "abc"}
*
* @param zero Value to start the accumulation with.
* @param accumulator The accumulator function.
* @return an accumulated version of this.
* @throws NullPointerException if {@code f} is null
*/
@Override
public U foldRight(U zero, BiFunction super T, ? super U, ? extends U> accumulator) {
Objects.requireNonNull(zero, "zero is null");
Objects.requireNonNull(accumulator, "accumulator is null");
return toList().foldRight(zero, accumulator);
}
@Override
public Map> groupBy(Function super T, ? extends C> classifier) {
return io.vavr.collection.Collections.groupBy(this, classifier, (elements) -> ofAll(comparator, elements));
}
@Override
public io.vavr.collection.Iterator extends PriorityQueue> grouped(int size) {
return sliding(size, size);
}
/**
* Checks if this {@link PriorityQueue} is known to have a finite size.
*
* This method should be implemented by classes only, i.e. not by interfaces.
*
* @return true, if this {@link PriorityQueue} is known to have a finite size, false otherwise.
*/
@Override
public boolean hasDefiniteSize() {
return true;
}
/**
* Dual of {@linkplain #tail()}, returning all elements except the last.
*
* @return a new instance containing all elements except the last.
* @throws UnsupportedOperationException if this is empty
*/
@Override
public PriorityQueue init() {
return ofAll(comparator, iterator().init());
}
/**
* Checks if this {@link PriorityQueue} can be repeatedly traversed.
*
* This method should be implemented by classes only, i.e. not by interfaces.
*
* @return true, if this {@link PriorityQueue} is known to be traversable repeatedly, false otherwise.
*/
@Override
public boolean isTraversableAgain() {
return true;
}
@Override
public T last() {
return Collections.last(this);
}
/**
* Computes the number of elements of this {@link PriorityQueue}.
*
* Same as {@link #size()}.
*
* @return the number of elements
*/
@Override
public int length() {
return size;
}
@Override
public PriorityQueue map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return map(Comparators.naturalComparator(), mapper);
}
public PriorityQueue map(Comparator comparator, Function super T, ? extends U> mapper) {
Objects.requireNonNull(comparator, "comparator is null");
Objects.requireNonNull(mapper, "mapper is null");
return ofAll(comparator, iterator().map(mapper));
}
/**
* Returns this {@code PriorityQueue} if it is nonempty,
* otherwise {@code PriorityQueue} created from iterable, using existing comparator.
*
* @param other An alternative {@code Traversable}
* @return this {@code PriorityQueue} if it is nonempty,
* otherwise {@code PriorityQueue} created from iterable, using existing comparator.
*/
@Override
public PriorityQueue orElse(Iterable extends T> other) {
return isEmpty() ? ofAll(comparator, other) : this;
}
/**
* Returns this {@code PriorityQueue} if it is nonempty,
* otherwise {@code PriorityQueue} created from result of evaluating supplier, using existing comparator.
*
* @param supplier An alternative {@code Traversable}
* @return this {@code PriorityQueue} if it is nonempty,
* otherwise {@code PriorityQueue} created from result of evaluating supplier, using existing comparator.
*/
@Override
public PriorityQueue orElse(Supplier extends Iterable extends T>> supplier) {
return isEmpty() ? ofAll(comparator, supplier.get()) : this;
}
@Override
public Tuple2 extends PriorityQueue, ? extends PriorityQueue> partition(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
PriorityQueue left = empty(comparator), right = left;
for (T t : this) {
if (predicate.test(t)) {
left = left.enqueue(t);
} else {
right = right.enqueue(t);
}
}
return Tuple.of(left, right);
}
@Override
public PriorityQueue replace(T currentElement, T newElement) {
Objects.requireNonNull(currentElement, "currentElement is null");
Objects.requireNonNull(newElement, "newElement is null");
return ofAll(comparator, iterator().replace(currentElement, newElement));
}
@Override
public PriorityQueue replaceAll(T currentElement, T newElement) {
Objects.requireNonNull(currentElement, "currentElement is null");
Objects.requireNonNull(newElement, "newElement is null");
return ofAll(comparator, iterator().replaceAll(currentElement, newElement));
}
@Override
public PriorityQueue scan(T zero, BiFunction super T, ? super T, ? extends T> operation) {
return io.vavr.collection.Collections.scanLeft(this, zero, operation, it -> ofAll(comparator, it));
}
@Override
public PriorityQueue scanLeft(U zero, BiFunction super U, ? super T, ? extends U> operation) {
return io.vavr.collection.Collections.scanLeft(this, zero, operation, it -> ofAll(Comparators.naturalComparator(), it));
}
@Override
public PriorityQueue scanRight(U zero, BiFunction super T, ? super U, ? extends U> operation) {
return io.vavr.collection.Collections.scanRight(this, zero, operation, it -> ofAll(Comparators.naturalComparator(), it));
}
@Override
public io.vavr.collection.Iterator extends PriorityQueue> slideBy(Function super T, ?> classifier) {
return iterator().slideBy(classifier).map(v -> ofAll(comparator, v));
}
@Override
public io.vavr.collection.Iterator extends PriorityQueue> sliding(int size) {
return iterator().sliding(size).map(v -> ofAll(comparator, v));
}
@Override
public io.vavr.collection.Iterator extends PriorityQueue> sliding(int size, int step) {
return iterator().sliding(size, step).map(v -> ofAll(comparator, v));
}
@Override
public Tuple2 extends PriorityQueue, ? extends PriorityQueue> span(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(takeWhile(predicate), dropWhile(predicate));
}
@Override
public PriorityQueue take(int n) {
if (n >= size() || isEmpty()) {
return this;
} else if (n <= 0) {
return empty(comparator);
} else {
return ofAll(comparator, iterator().take(n));
}
}
@Override
public PriorityQueue takeRight(int n) {
if (n >= size() || isEmpty()) {
return this;
} else if (n <= 0) {
return empty(comparator);
} else {
return ofAll(comparator, toArray().takeRight(n));
}
}
@Override
public PriorityQueue takeUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return isEmpty() ? this : ofAll(comparator, iterator().takeUntil(predicate));
}
@Override
public Tuple2 extends PriorityQueue, ? extends PriorityQueue> unzip(Function super T, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
final Tuple2, io.vavr.collection.Iterator> unzip = iterator().unzip(unzipper);
return Tuple.of(ofAll(Comparators.naturalComparator(), unzip._1), ofAll(Comparators.naturalComparator(), unzip._2));
}
@Override
public Tuple3 extends PriorityQueue, ? extends PriorityQueue, ? extends PriorityQueue> unzip3(Function super T, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
final Tuple3, io.vavr.collection.Iterator, io.vavr.collection.Iterator> unzip3 = iterator().unzip3(unzipper);
return Tuple.of(ofAll(Comparators.naturalComparator(), unzip3._1), ofAll(Comparators.naturalComparator(), unzip3._2), ofAll(Comparators.naturalComparator(), unzip3._3));
}
@Override
public PriorityQueue> zip(Iterable extends U> that) {
return zipWith(that, Tuple::of);
}
@Override
public PriorityQueue zipWith(Iterable extends U> that, BiFunction super T, ? super U, ? extends R> mapper) {
Objects.requireNonNull(that, "that is null");
Objects.requireNonNull(mapper, "mapper is null");
return ofAll(Comparators.naturalComparator(), iterator().zipWith(that, mapper));
}
@Override
public PriorityQueue> zipAll(Iterable extends U> that, T thisElem, U thatElem) {
Objects.requireNonNull(that, "that is null");
return ofAll(iterator().zipAll(that, thisElem, thatElem));
}
@Override
public PriorityQueue> zipWithIndex() {
return zipWithIndex(Tuple::of);
}
@Override
public PriorityQueue zipWithIndex(BiFunction super T, ? super Integer, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return ofAll(Comparators.naturalComparator(), iterator().zipWithIndex(mapper));
}
@Override
public String stringPrefix() {
return "PriorityQueue";
}
@Override
public boolean equals(Object o) {
return o == this || o instanceof PriorityQueue && io.vavr.collection.Collections.areEqual(this, (Iterable) o);
}
@Override
public int hashCode() {
return io.vavr.collection.Collections.hashOrdered(this);
}
@Override
@SuppressWarnings("unchecked")
public Comparator comparator() {
return (Comparator) comparator;
}
}
final class PriorityQueueBase {
/**
* fun deleteMin [] = raise EMPTY
* * | deleteMin ts =
* * val (Node (x,r,c), ts) = getMin ts
* * val (ts',xs') = split ([],[],c)
* * in fold insert xs' (meld (ts, ts')) end
**/
static Tuple2>> deleteMin(Comparator super T> comparator, Seq> forest) {
/* get the minimum tree and the rest of the forest */
final Node minTree = findMin(comparator, forest);
final Seq> forestTail = (minTree == forest.head()) ? forest.tail() : forest.remove(minTree);
final Seq> newForest = rebuild(comparator, minTree.children);
return Tuple.of(minTree.root, meld(comparator, newForest, forestTail));
}
/**
* fun insert (x, ts as t1 :: t2 :: rest) =
* * if rank t1 = rank t2 then skewLink(Node(x,0,[]),t1,t2) :: rest
* * else Node (x,0,[]) :: ts
* * | insert (x, ts) = Node (x,0,[]) :: ts
**/
static Seq> insert(Comparator super T> comparator, T element, Seq> forest) {
final Node tree = Node.of(element, 0, io.vavr.collection.List.empty());
if (forest.size() >= 2) {
final Seq> tail = forest.tail();
final Node t1 = forest.head(), t2 = tail.head();
if (t1.rank == t2.rank) {
return tree.skewLink(comparator, t1, t2).appendTo(tail.tail());
}
}
return tree.appendTo(forest);
}
/** fun meld (ts, ts') = meldUniq (uniqify ts, uniqify ts') */
static Seq> meld(Comparator super T> comparator, Seq> source, Seq> target) {
return meldUnique(comparator, uniqify(comparator, source), uniqify(comparator, target));
}
/**
* Find the minimum root in the forest
*
* fun findMin [] = raise EMPTY
* * | findMin [t] = root t
* * | findMin (t :: ts) =
* * let val x = findMin ts
* * in if Elem.leq (root t, x) then root t else x end
*/
static Node findMin(Comparator super T> comparator, Seq> forest) {
final io.vavr.collection.Iterator> iterator = forest.iterator();
Node min = iterator.next();
for (Node node : iterator) {
if (comparator.compare(node.root, min.root) < 0) {
min = node;
}
}
return min;
}
/**
* Separate the rank 0 trees from the rest, rebuild the 0 rank ones and merge them back
*
* fun split (ts,xs,[]) = (ts, xs)
* * | split (ts,xs,t :: c) =
* * if rank t = 0 then split (ts,root t :: xs,c)
* * else split (t :: ts,xs,c)
*/
private static Seq> rebuild(Comparator super T> comparator, Seq> forest) {
Seq> nonZeroRank = io.vavr.collection.List.empty(), zeroRank = io.vavr.collection.List.empty();
for (; !forest.isEmpty(); forest = forest.tail()) {
final Node initialForestHead = forest.head();
if (initialForestHead.rank == 0) {
zeroRank = insert(comparator, initialForestHead.root, zeroRank);
} else {
nonZeroRank = initialForestHead.appendTo(nonZeroRank);
}
}
return meld(comparator, nonZeroRank, zeroRank);
}
/**
* fun uniqify [] = []
* * | uniqify (t :: ts) = ins (t, ts) (∗ eliminate initial duplicate ∗)
**/
private static Seq> uniqify(Comparator super T> comparator, Seq> forest) {
return forest.isEmpty()
? forest
: ins(comparator, forest.head(), forest.tail());
}
/**
* fun ins (t, []) = [t]
* * | ins (t, t' :: ts) = (∗ rank t ≤ rank t' ∗)
* * if rank t < rank t' then t :: t' :: ts
* * else ins (link (t, t'), ts)
*/
private static Seq> ins(Comparator super T> comparator, Node tree, Seq> forest) {
while (!forest.isEmpty() && tree.rank == forest.head().rank) {
tree = tree.link(comparator, forest.head());
forest = forest.tail();
}
return tree.appendTo(forest);
}
/**
* fun meldUniq ([], ts) = ts
* * | meldUniq (ts, []) = ts
* * | meldUniq (t1 :: ts1, t2 :: ts2) =
* * if rank t1 < rank t2 then t1 :: meldUniq (ts1, t2 :: ts2)
* * else if rank t2 < rank t1 then t2 :: meldUniq (t1 :: ts1, ts2)
* * else ins (link (t1, t2), meldUniq (ts1, ts2))
**/
private static Seq> meldUnique(Comparator super T> comparator, Seq> forest1, Seq> forest2) {
if (forest1.isEmpty()) {
return forest2;
} else if (forest2.isEmpty()) {
return forest1;
} else {
final Node tree1 = forest1.head(), tree2 = forest2.head();
if (tree1.rank == tree2.rank) {
final Node tree = tree1.link(comparator, tree2);
final Seq> forest = meldUnique(comparator, forest1.tail(), forest2.tail());
return ins(comparator, tree, forest);
} else {
if (tree1.rank < tree2.rank) {
final Seq> forest = meldUnique(comparator, forest1.tail(), forest2);
return tree1.appendTo(forest);
} else {
final Seq> forest = meldUnique(comparator, forest1, forest2.tail());
return tree2.appendTo(forest);
}
}
}
}
/* Based on http://www.brics.dk/RS/96/37/BRICS-RS-96-37.pdf */
static final class Node implements Serializable {
private static final long serialVersionUID = 1L;
final T root;
final int rank;
final Seq> children;
private Node(T root, int rank, Seq> children) {
this.root = root;
this.rank = rank;
this.children = children;
}
static Node of(T value, int rank, Seq> children) {
return new Node<>(value, rank, children);
}
/*
* fun link (t1 as Node (x1,r1,c1), t2 as Node (x2,r2,c2)) = (∗ r1 = r2 ∗)
* * if Elem.leq (x1,x2) then Node (x1,r1+1,t2 :: c1)
* * else Node (x2,r2+1,t1 :: c2
*/
Node link(Comparator super T> comparator, Node tree) {
return comparator.compare(this.root, tree.root) <= 0
? of(this.root, this.rank + 1, tree.appendTo(this.children))
: of(tree.root, tree.rank + 1, this.appendTo(tree.children));
}
/*
* fun skewLink (t0 as Node (x0,r0, _), t1 as Node (x1,r1,c1), t2 as Node (x2,r2,c2)) =
* * if Elem.leq (x1,x0) andalso Elem.leq (x1,x2) then Node (x1,r1+1,t0 :: t2 :: c1)
* * else if Elem.leq (x2,x0) andalso Elem.leq (x2,x1) then Node (x2,r2+1,t0 :: t1 :: c2)
* * else Node (x0,r1+1,[t1, t2])
*/
Node skewLink(Comparator super T> comparator, Node left, Node right) {
if (comparator.compare(left.root, root) <= 0 && comparator.compare(left.root, right.root) <= 0) {
return of(left.root, left.rank + 1, appendTo(right.appendTo(left.children)));
} else if (comparator.compare(right.root, root) <= 0) {
return of(right.root, right.rank + 1, appendTo(left.appendTo(right.children)));
} else {
return of(root, left.rank + 1, io.vavr.collection.List.of(left, right));
}
}
Seq> appendTo(Seq> forest) {
return forest.prepend(this);
}
}
}