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

de.chrlembeck.util.algorithm.Algorithms Maven / Gradle / Ivy

package de.chrlembeck.util.algorithm;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * Utility-Klasse Zur einfachen Verwendung ausgewählter Standard-Algorithmen.
 *
 * @author Christoph Lembeck
 */
public final class Algorithms {

    /**
     * private constructor
     */
    private Algorithms() {
    }

    /**
     * Führt eine Tiefensuche durch gibt bei Fund eines den Suchkriterien entsprechenden Zusatdns die Liste der
     * Zustände, die zu dem Treffer geführt haben zurück.
     * 
     * @param state
     *            Startzustand für den Beginn der Tiefensuche.
     * @param stateProducer
     *            Producer zur Erzeugung einer Liste von Nachfolgezuständen zu dem ihm übergebenen Zustand.
     * @param consumer
     *            Consumer zur Verarbeitung aller während der Suche generierten Zustände. Falls die Zwischenzustände
     *            nicht verarbieter werden sollen kann hier null übergeben werden.
     * @param acceptanceCriterion
     *            Prüfkriterium für die Erkennung des gesuchten Zustands. Ist das Prüfkriterium erfüllt, wird die Suche
     *            beendet und die bis zur Erreichung des gefundenen Zustands durchlaufenen Zustände werden als Ergebnis
     *            zurückgegeben.
     * 
     * @param 
     *            Typ der Objekte für die Speicherung der Zwischenzustände.
     * @return Liste der bis zum Erreichen des gesuchten Zustands durchlaufenen Zwischenzustände inklusive Start- und
     *         Zielzustand. Null, falls kein erzeugter Zustand dem Suchkriterium entsprochen hat.
     */
    public static final  List breadthFirstSearch(final State state,
            final Function, Iterable> stateProducer,
            final Consumer> consumer, final Predicate> acceptanceCriterion) {
        // Queue zur Aufbewahrung der noch zu verarbeitenden Zwischenzustände.
        final Queue> queue = new LinkedList<>();
        // Referenz auf den als nächstes zu Verarbeitenden Zustand.
        StateWrapper currentState = new StateWrapper<>(state, null);
        // Queue mit dem Startzustand befüllen, damit mit diesem begonnen werden kann.
        queue.add(currentState);
        // Falls gewünscht, aktuellen Zustand an einen Consumer übermitteln.
        if (consumer != null) {
            consumer.accept(currentState);
        }
        // Suchen, bis keine Zwischenzustände mehr vorhanden sind.
        while (!queue.isEmpty()) {
            // nächsten aktuellen Zustand aus der Wareschlange nehmen.
            currentState = queue.poll();
            // neue Zwischenzustände auf Grundlage des aktuellen Zustand ermitteln lassen.
            final Iterable possibleStates = stateProducer.apply(currentState);
            // die neuen Zwischenzustände verarbeiten
            for (final State possibleState : possibleStates) {
                // Die erzeugten Zustände in den Wrapper packen, damit ihre Verbindung zu ihren Vorgängern abfragbar
                // bleiben.
                final StateWrapper newState = new StateWrapper<>(possibleState, currentState);
                // Falls gewünscht, aktuellen Zustand an einen Consumer übermitteln.
                if (consumer != null) {
                    consumer.accept(newState);
                }
                // prüfen, ob der neue Zustand bereits dem Suchkriterium entspricht.
                if (acceptanceCriterion.test(newState)) {
                    // bei einem Treffer Liste der Zwischenzustände zusammen mit dem Treffer ausgeben.
                    return newState.getStates();
                }
                // Lag kein Treffer vor, wird der Zusand in die Warteschlange gepackt und es geht mit dem nächsten
                // Zustand weiter...
                queue.add(newState);
            }
        }
        // Gibt es keine Zwischenzustände mehr, die bearbeitet werden müssen und lag bis dahin noch kein Treffer vor,
        // ist das Ergebnis null.
        return null;
    }

    /**
     * Wrapper-Klasse für die Speicherung eines Zwischenzustands für die Breitensuche. Neben dem Zustand selbst wird
     * hier auch die Referenz auf den Vorgänger, aus dem dieser Zustand entstanden ist gespeichert.
     * 
     * @author Christoph Lembeck
     *
     * @param 
     *            Typ des zu speichernden Zustand-Objekts.
     */
    public static class StateWrapper {

        /**
         * Referenz auf den hinterlegten Zustand.
         */
        private final State state;

        /**
         * Referenz auf einen ggf. vorhandenen Vorgänger dieses Zustands.
         */
        private final StateWrapper predecessor;

        /**
         * Erzeugt einen neuen Wrapper um den übergebenen Zustand mit Referenz auf den übergebenen Vorgänger.
         * 
         * @param state
         *            Zustand, der in dem Objekt festgehalten werden soll
         * @param predecessor
         *            Referenz auf einen ggf. vorhandenen Vorgängerzustand.
         */
        StateWrapper(final State state, final StateWrapper predecessor) {
            this.state = state;
            this.predecessor = predecessor;
        }

        /**
         * Gibt den enthaltenen Zustand zurück.
         * 
         * @return Im Wrapper enthaltenes Zustands-Objekt.
         */
        public State getState() {
            return state;
        }

        /**
         * Gibt den Vorgänger dieses Zustands zurück oder null, falls es keinen Vorgänger für den Zustand gibt.
         * 
         * @return Referenz auf den Vorgängerzustand oder null, falls kein solcher existiert.
         */
        public StateWrapper getPredecessor() {
            return predecessor;
        }

        /**
         * Erzeugt eine Liste von Zuständen, in der Reihenfolge, in der der Algorithmus diese durchwandert hat. Der
         * erste Zustand entspricht dabei dem Ausgangszustand und der letzte dem Zielzustand.
         * 
         * @return Liste der Zustände vom Ausgang bis zum Ziel.
         */
        public List getStates() {
            final List stateList;
            if (predecessor == null) {
                stateList = new ArrayList<>();
            } else {
                stateList = predecessor.getStates();
            }
            stateList.add(state);
            return stateList;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy