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

fj.data.PriorityQueue Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
package fj.data;

import fj.Equal;
import fj.F;
import fj.F2;
import fj.Monoid;
import fj.Ord;
import fj.P;
import fj.P2;
import fj.Show;
import fj.data.fingertrees.FingerTree;

import static fj.Function.compose;
import static fj.data.Option.none;
import static fj.data.Option.some;

/**
 * A priority queue implementation backed by a
 * {@link fj.data.fingertrees.FingerTree}.  The finger tree nodes are
 * annotated with type K, are combined using a monoid of K and both the
 * key and value are stored in the leaf.  Priorities of the same value
 * are returned FIFO (first in, first out).
 *
 * Created by MarkPerry on 31 May 16.
 */
public final class PriorityQueue {

    private final FingerTree> ftree;
    private final Equal equal;

    private PriorityQueue(Equal e, FingerTree> ft) {
        equal = e;
        ftree = ft;
    }

    /**
     * Creates a priority queue from a finger tree.
     */
    public static  PriorityQueue priorityQueue(Equal e, FingerTree> ft) {
        return new PriorityQueue<>(e, ft);
    }

    /**
     * Creates an empty priority queue.
     *
     * @param m A monoid to combine node annotations.
     * @param e A value to compare key equality.
     */
    public static  PriorityQueue empty(Monoid m, Equal e) {
        return priorityQueue(e, FingerTree.empty(m, P2.__1()));
    }

    /**
     * An empty priority queue with integer priorities.
     */
    public static  PriorityQueue emptyInt() {
        return empty(Monoid.intMaxMonoid, Equal.intEqual);
    }

    /**
     * Maps the values in each node with function f.
     */
    public  PriorityQueue map(F f) {
        return priorityQueue(equal,
                ftree.map(P2.map2_(f),
                        FingerTree.measured(ftree.measured().monoid(), P2.__1())
                )
        );
    }

    /**
     * Filters nodes based on the value inside each node.
     */
    public PriorityQueue filterValues(F f) {
        return priorityQueue(equal, ftree.filter(p2 -> f.f(p2._2())));
    }

    /**
     * Filters the nodes based on the annotation of each node.
     */
    public PriorityQueue filterKeys(F f) {
        return priorityQueue(equal, ftree.filter(p2 -> f.f(p2._1())));
    }

    /**
     * Is the tree empty?
     */
    public boolean isEmpty() {
        return ftree.isEmpty();
    }

    /**
     * If the tree is not empty, returns the node with highest priority otherwise returns nothing.
     */
    public Option> top() {
        return unqueue(none(), (top, tail) -> some(top));
    }

    /**
     * Returns all the elements of the queue with the highest (same) priority.
     */
    public List> topN() {
        return toStream().uncons(
            List.nil(),
            top -> tail -> List.cons(top, tail._1().takeWhile(compose(equal.eq(top._1()), P2.__1())).toList())
        );
    }

    /**
     * Adds a node with priority k and value a.  This operation take O(1).
     */
    public PriorityQueue enqueue(K k, A a) {
        return priorityQueue(equal, ftree.snoc(P.p(k, a)));
    }

    /**
     * Adds nodes using the list of products with priority k and value a.  This operation takes O(list.length()).
     */
    public PriorityQueue enqueue(List> list) {
        return list.foldLeft((pq, p) -> pq.enqueue(p._1(), p._2()), this);
    }

    /**
     * Does the priority k exist already?
     */
    public boolean contains(final K k) {
        return !ftree.split(equal.eq(k))._2().isEmpty();
    }

    /**
     * Adds nodes using the iterable of products with priority k and value a.
     */
    public PriorityQueue enqueue(Iterable> it) {
        PriorityQueue result = this;
        for (P2 p: it) {
            result = result.enqueue(p);
        }
        return result;
    }

    /**
     * Adds a node with priority k and value a.  This operation take O(1).
     */
    public PriorityQueue enqueue(P2 p) {
        return enqueue(p._1(), p._2());
    }

    /**
     * Removes the node with the highest priority.
     */
    public PriorityQueue dequeue() {
        return unqueue(this, (top, tail) -> tail);
    }

    /**
     * Returns a tuple of the node with the highest priority and the rest of the priority queue.
     */
    public P2>, PriorityQueue> topDequeue() {
        return unqueue(P.p(none(), this), (top, tail) -> P.p(some(top), tail));
    }

    /**
     * Performs a reduction on this priority queue using the given arguments.
     *
     * @param empty  The value to return if this queue is empty.
     * @param topDequeue The function to apply to the top priority element and the tail of the queue (without its top element).
     * @return A reduction on this queue.
     */
    public  B unqueue(B empty, F2, PriorityQueue, B> topDequeue) {
        K top = ftree.measure();
        P2>, FingerTree>> p = ftree.split(equal.eq(top));
        return p._2().uncons(
            empty,
            (head, tail) -> topDequeue.f(head, priorityQueue(equal, p._1().append(tail)))
        );
    }

    /**
     * Removes the top n elements with the highest priority.
     */
    public PriorityQueue dequeue(int n) {
        int i = n;
        PriorityQueue result = this;
        while (i > 0) {
            i--;
            result = result.dequeue();
        }
        return result;
    }

    /**
     * Does the top of the queue have lower priority than k?
     */
    public boolean isLessThan(Ord ok, K k) {
        return top().option(true, p -> ok.isLessThan(p._1(), k));
    }

    public boolean isGreaterThan(Ord ok, K k) {
        return top().option(false, p -> ok.isGreaterThan(p._1(), k));
    }

    public boolean isEqual(Ord ok, K k) {
        return top().option(false, p -> ok.eq(p._1(), k));
    }

    /**
     * Returns a stream of products with priority k and value a.
     */
    public Stream> toStream() {
        return unqueue(Stream.nil(), (top, tail) -> Stream.cons(top, () -> tail.toStream()));
    }

    /**
     * Returns a list of products with priority k and value a.
     */
    public List> toList() {
        return toStream().toList();
    }

    public String toString() {
        return Show.priorityQueueShow(Show.anyShow(), Show.anyShow()).showS(this);
    }

}