/* * Java Genetic Algorithm Library (@__identifier__@). * Copyright (c) @__year__@ Franz Wilhelmstötter * * 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. * * Author: * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at) */ package org.jenetics.internal.util; import static org.jenetics.internal.util.array.swap; /** * Implementations of this class doesn't sort the given array directly, instead * an index lookup array is returned which allows to access the array in * an sorted order. The arrays are sorted in descending order. * * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> * @since 3.0 * @version 3.0 */ public abstract class IndexSorter { // This value has been chosen after JMH benchmarking. // Benchmark Mode Samples Score Score error Units // o.j.i.u.IndexSorterPerf.heapSort160 avgt 14 5560.895 80.158 ns/op // o.j.i.u.IndexSorterPerf.heapSort250 avgt 14 9516.441 119.648 ns/op // o.j.i.u.IndexSorterPerf.heapSort320 avgt 14 12722.461 103.487 ns/op // o.j.i.u.IndexSorterPerf.heapSort80 avgt 14 2473.058 27.884 ns/op // o.j.i.u.IndexSorterPerf.insertionSort160 avgt 14 10877.158 550.338 ns/op // o.j.i.u.IndexSorterPerf.insertionSort250 avgt 14 25731.100 925.196 ns/op // o.j.i.u.IndexSorterPerf.insertionSort320 avgt 14 41864.108 1801.247 ns/op // o.j.i.u.IndexSorterPerf.insertionSort80 avgt 14 2643.726 165.315 ns/op //private static final int INSERTION_SORT_THRESHOLD = 80; private static final int INSERTION_SORT_THRESHOLD = 80; static final IndexSorter INSERTION_SORTER = new InsertionSorter(); static final IndexSorter HEAP_SORTER = new HeapSorter(); /** * This method must be implemented by the different sorting algorithms. * * @param array the array to sort * @param indexes the index lookup array - * ∀ i ∈ [0, N): index[i] = i * @return the given {@code indexes} which is now "sorted" */ abstract int[] sort(final double[] array, final int[] indexes); /** * Return an new sorted index lookup array. The given array is not touched. * * @param array the array to sort. * @return the index lookup array */ public static int[] sort(final double[] array) { final IndexSorter sorter = array.length < INSERTION_SORT_THRESHOLD ? INSERTION_SORTER : HEAP_SORTER; return sorter.sort(array, indexes(array.length)); } static int[] indexes(final int length) { final int[] indexes = new int[length]; for (int i = length; --i >= 0;) { indexes[i] = i; } return indexes; } @Override public String toString() { return getClass().getSimpleName(); } } /** * Heap sort implementation. */ final class HeapSorter extends IndexSorter { @Override int[] sort(final double[] array, final int[] indexes) { // Heapify for (int k = array.length/2; k >= 0; --k) { sink(array, indexes, k, array.length); } // Sort down. for (int i = array.length; --i >= 1;) { swap(indexes, 0, i); sink(array, indexes, 0, i); } return indexes; } private static void sink( final double[] array, final int[] indexes, final int start, final int end ) { int m = start; while (2*m < end) { int j = 2*m; if (j < end - 1 && array[indexes[j]] > array[indexes[j + 1]]) ++j; if (array[indexes[m]] <= array[indexes[j]]) break; swap(indexes, m, j); m = j; } } } /** * Insertion sort implementation. */ final class InsertionSorter extends IndexSorter { @Override int[] sort(final double[] array, final int[] indexes) { for (int i = 1, n = array.length; i < n; ++i) { int j = i; while (j > 0) { if (array[indexes[j - 1]] < array[indexes[j]]) { swap(indexes, j - 1, j); } else { break; } --j; } } return indexes; } }