// Copyright(C) 1999-2020 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details #include "iqsort.h" #include #include namespace { template void iqsort(const T v[], INT iv[], size_t left, size_t right); template void iisort(const T v[], INT iv[], size_t N); template void check(const T v[], INT iv[], size_t N); } // namespace template void index_qsort(const T v[], INT iv[], size_t N) { if (N <= 1) { return; } iqsort(v, iv, 0, N - 1); iisort(v, iv, N); #if defined(DEBUG_QSORT) check(v, iv, N); #endif } // The following are not part of the public interFace... namespace { /* The following 'indexed qsort' routine is modified from Sedgewicks * algorithm It selects the pivot based on the median of the left, * right, and center values to try to avoid degenerate cases ocurring * when a single value is chosen. It performs a quicksort on * intervals down to the QSORT_CUTOFF size and then performs a final * insertion sort on the almost sorted final array. Based on data in * Sedgewick, the QSORT_CUTOFF value should be between 5 and 20. * * See Sedgewick for further details Define DEBUG_QSORT at the top of * this file and recompile to compile in code that verifies that the * array is sorted. */ #define QSORT_CUTOFF 12 /* swap - interchange v[i] and v[j] */ template void swap_(INT v[], size_t i, size_t j) { #if 0 INT temp; temp = v[i]; v[i] = v[j]; v[j] = temp; #else std::swap(v[i], v[j]); #endif } template void order3(T v[], INT iv[], size_t left, size_t center, size_t right) { if (v[iv[left]] > v[iv[center]]) { swap_(iv, left, center); } if (v[iv[left]] > v[iv[right]]) { swap_(iv, left, right); } if (v[iv[center]] > v[iv[right]]) { swap_(iv, center, right); } } template size_t median3(const T v[], INT iv[], size_t left, size_t right) { size_t center = (left + right) / 2; size_t pl = left; size_t pm = center; size_t pr = right; if (right - left > 40) { size_t s = (right - left) / 8; order3(v, iv, left, left + s, left + 2 * s); order3(v, iv, center - s, center, center + s); order3(v, iv, right - 2 * s, right - s, right); // Now set up to get median of the 3 medians... pl = left + s; pm = center; pr = right - s; } order3(v, iv, pl, pm, pr); swap_(iv, center, right - 1); return iv[right - 1]; } template void iqsort(const T v[], INT iv[], size_t left, size_t right) { if (left + QSORT_CUTOFF <= right) { size_t pivot = median3(v, iv, left, right); size_t i = left; size_t j = right - 1; for (;;) { while (v[iv[++i]] < v[pivot]) { ; } while (v[iv[--j]] > v[pivot]) { ; } if (i < j) { swap_(iv, i, j); } else { break; } } swap_(iv, i, right - 1); iqsort(v, iv, left, i - 1); iqsort(v, iv, i + 1, right); } } template void iisort(const T v[], INT iv[], size_t N) { size_t j; size_t ndx = 0; if (N <= 1) { return; } T low = v[iv[0]]; for (size_t i = 1; i < N; i++) { if (v[iv[i]] < low) { low = v[iv[i]]; ndx = i; } } /* Put lowest value in slot 0 */ swap_(iv, 0, ndx); for (size_t i = 1; i < N; i++) { INT tmp = iv[i]; for (j = i; v[tmp] < v[iv[j - 1]]; j--) { iv[j] = iv[j - 1]; } iv[j] = tmp; } } template void check(const T v[], INT iv[], size_t N) { fmt::print(stderr, "Checking sort of {:n} values\n", N + 1); size_t i; for (i = 1; i < N; i++) { SMART_ASSERT(v[iv[i - 1]] <= v[iv[i]]); } } } // namespace template void index_qsort(const int v[], int iv[], size_t N); template void index_qsort(const double v[], int iv[], size_t N); template void index_qsort(const int64_t v[], int64_t iv[], size_t N); template void index_qsort(const double v[], int64_t iv[], size_t N);