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
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);
|