Cloned SEACAS for EXODUS library with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.4 KiB

2 years ago
// 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 <cstdint>
#include <fmt/ostream.h>
namespace {
template <typename T, typename INT> void iqsort(const T v[], INT iv[], size_t left, size_t right);
template <typename T, typename INT> void iisort(const T v[], INT iv[], size_t N);
template <typename T, typename INT> void check(const T v[], INT iv[], size_t N);
} // namespace
template <typename T, typename INT> 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 <typename INT> 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 <typename T, typename INT>
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 <typename T, typename INT>
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 <typename T, typename INT> 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 <typename T, typename INT> 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 <typename T, typename INT> 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);