Генератор перестановок
Пишу про класичну задачу генерації перестановок з n елементів, так про ту саму, кількість перестановок у якій n!. Потрібно було реалізувати її на Java. Задача, повторюся, класична, і можна знайти чимало інформації про алгоритм її розв’язання, однак дане розв’язання здалося мені досить компактним та цікавим.
В основі лежить рекурсивний алгоритм. На кожному рекурсивному вході формується новий елемент перестановки. Глибина рекурсії, таким чином, рівна n. Для формування перестановки використовується бітова карта – екземпляр класу java.util.BitSet, що і є головним фактором простоти алгоритму. Викорстання даної реалізації є дуже простим:
[sourcecode language='java'] PermutationsHelper.generate(elementsCollection, handler); [/sourcecode]
Тут elementsCollection – екзмепляр класу, що настлідує java.util.Collection,
handler – об’єкт, що містить метод для обробки кожної з перестановок, на приклад, для виведеня на екран:
[sourcecode language='java']
/** Колекція елементів. */
elementsCollection = Arrays.asList("a", "b", "c", "d");
handler = new PrintHandler();
.....
/**
* Виводить на екран перестановку елементів класу String.
*/
public class PrintHandler implements PermutationsHandler {
@Override
public void handle(final ArrayList permutation) {
System.out.println(permutation);
}
}
[/sourcecode]
Люблю побавитися за Java Generics…
Словом, дивіться:
[sourcecode language='java'] import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; /** * This class helps to generate permutations of elements. */ public class PermutationsHelper{ /** Handler. */ private PermutationHandler handler; /** Bitmap to identify used elements. */ private BitSet bitmap; /** Elements to permutate. */ private ArrayList elements; /** Current permutation. */ private ArrayList permutation; /** Hidden constructor. */ private PermutationsHelper() { } /** * Does a change in the permutation. * @param iteration iteration index (recursion depth) */ private void change(final int iteration) { if (iteration == permutation.size()) { handler.handle(permutation); return; } for (int i = bitmap.nextSetBit(0); i >= 0; i = bitmap.nextSetBit(i + 1)) { permutation.set(iteration, elements.get(i)); bitmap.clear(i); change(iteration + 1); bitmap.set(i); }; } /** * Generates permutations for the elements collection and calls a handler * for the each new permutation. * @param elements type * @param elements elements collection * @param handler permutation handler */ public static void generate(final Collection elements, final PermutationHandler handler) { PermutationsHelper helper = new PermutationsHelper (); helper.elements = new ArrayList (elements); helper.permutation = new ArrayList (elements); helper.handler = handler; helper.bitmap = new BitSet(elements.size()); helper.bitmap.set(0, elements.size()); helper.change(0); } /** * Permutation handler interface. * @param elements type */ public static interface PermutationHandler { void handle(final ArrayList permutation); } /** * Starts the test. * @param args arguments are ignored */ public static void main(final String[] args) { PermutationsHelper.generate( Arrays.asList("a", "b", "c", "d"), new PermutationHandler () { @Override public void handle(final ArrayList permutation) { System.out.println(permutation); } } ); } } [/sourcecode]
Але це ще не все. Оскільки я останнім часом став фаном Groovy, то покажу ще, як можна використати даний генератор за допомогою цієї мови. Додамо до нашого класу PermutationsHelper ще один метод:
[sourcecode language='java'] import groovy.lang.Closure; .... public staticvoid generate(final Collection elements, final Closure closure) { generate(elements, new PermutationHandler () { @Override public void handle(final ArrayList permutation) { closure.call(permutation); } }); } [/sourcecode]
Тепер, для Groovy, попередній приклад буде виглядати наступним чином:
[sourcecode language='java']
PermutationsHelper.generate(["a", "b", "c", "d"]) {
println it
}
[/sourcecode]






Пока нет комментариев.