All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vavr.collection.PriorityQueue Maven / Gradle / Ivy

There is a newer version: 1.0.0-alpha-4
Show newest version
/*  __    __  __  __    __  ___
 * \  \  /  /    \  \  /  /  __/
 *  \  \/  /  /\  \  \/  /  /
 *   \____/__/  \__\____/__/
 *
 * 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 comparator;
    private final Seq> forest;
    private final int size;

    private PriorityQueue(Comparator 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 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 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 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} 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 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 comparator, T element) {
        return ofAll(comparator, io.vavr.collection.List.of(element));
    }

    @SuppressWarnings("unchecked")
    public static  PriorityQueue of(Comparator comparator, T... elements) {
        return ofAll(comparator, io.vavr.collection.List.of(elements));
    }

    public static > PriorityQueue ofAll(Iterable elements) {
        return ofAll(Comparators.naturalComparator(), elements);
    }

    @SuppressWarnings("unchecked")
    public static  PriorityQueue ofAll(Comparator comparator, Iterable 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 javaStream) {
        return ofAll(Comparators.naturalComparator(), io.vavr.collection.Iterator.ofAll(javaStream.iterator()));
    }

    public static  PriorityQueue ofAll(Comparator comparator, java.util.stream.Stream 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 function) {
        Objects.requireNonNull(function, "function is null");
        final Comparator 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 supplier) {
        Objects.requireNonNull(supplier, "supplier is null");
        final Comparator 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 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 comparator) {
        Objects.requireNonNull(comparator, "comparator is null");
        return isEmpty() ? this : ofAll(comparator, iterator().distinctBy(comparator));
    }

    @Override
    public  PriorityQueue distinctBy(Function 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 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 predicate) {
        Objects.requireNonNull(predicate, "predicate is null");
        if (isEmpty()) {
            return this;
        } else {
            return ofAll(comparator, iterator().filter(predicate));
        }
    }

    @Override
    public  PriorityQueue flatMap(Function> mapper) {
        return flatMap(Comparators.naturalComparator(), mapper);
    }

    public  PriorityQueue flatMap(Comparator comparator, Function> 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 accumulator) { Objects.requireNonNull(zero, "zero is null"); Objects.requireNonNull(accumulator, "accumulator is null"); return toList().foldRight(zero, accumulator); } @Override public Map> groupBy(Function classifier) { return io.vavr.collection.Collections.groupBy(this, classifier, (elements) -> ofAll(comparator, elements)); } @Override public io.vavr.collection.Iterator> 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 mapper) { Objects.requireNonNull(mapper, "mapper is null"); return map(Comparators.naturalComparator(), mapper); } public PriorityQueue map(Comparator comparator, Function 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 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> supplier) { return isEmpty() ? ofAll(comparator, supplier.get()) : this; } @Override public Tuple2, ? extends PriorityQueue> partition(Predicate 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 operation) { return io.vavr.collection.Collections.scanLeft(this, zero, operation, it -> ofAll(comparator, it)); } @Override public PriorityQueue scanLeft(U zero, BiFunction operation) { return io.vavr.collection.Collections.scanLeft(this, zero, operation, it -> ofAll(Comparators.naturalComparator(), it)); } @Override public PriorityQueue scanRight(U zero, BiFunction operation) { return io.vavr.collection.Collections.scanRight(this, zero, operation, it -> ofAll(Comparators.naturalComparator(), it)); } @Override public io.vavr.collection.Iterator> slideBy(Function classifier) { return iterator().slideBy(classifier).map(v -> ofAll(comparator, v)); } @Override public io.vavr.collection.Iterator> sliding(int size) { return iterator().sliding(size).map(v -> ofAll(comparator, v)); } @Override public io.vavr.collection.Iterator> sliding(int size, int step) { return iterator().sliding(size, step).map(v -> ofAll(comparator, v)); } @Override public Tuple2, ? extends PriorityQueue> span(Predicate 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 predicate) { Objects.requireNonNull(predicate, "predicate is null"); return isEmpty() ? this : ofAll(comparator, iterator().takeUntil(predicate)); } @Override public Tuple2, ? extends PriorityQueue> unzip(Function> 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> unzip3(Function> 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 that) { return zipWith(that, Tuple::of); } @Override public PriorityQueue zipWith(Iterable that, BiFunction 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 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 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 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 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 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 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 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 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 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 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 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 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); } } }