TrSort  v0.3.0
A novel sorting algorithm I've invented
tr-sort.hpp
Go to the documentation of this file.
1 
17 #ifndef COM_SAXBOPHONE_TR_SORT_HPP
18 #define COM_SAXBOPHONE_TR_SORT_HPP
19 
20 #include <cmath> // ceil, nextafter, pow
21 #include <cstddef>
22 #include <span>
23 #include <type_traits>
24 #include <vector>
25 
26 
43  template <
44  typename T,
45  std::size_t Extent = std::dynamic_extent,
46  typename Real = long double
47  >
48  void sort(std::span<T, Extent> data) {
49  // don't sort data of length {0..1}
50  if (data.size() < 2) {
51  return;
52  }
53  // gather stats on first pass of data
54  std::size_t size = data.size();
55  T min, max;
56  if constexpr (std::is_floating_point<T>::value) {
57  min = +std::numeric_limits<T>::infinity();
58  max = -std::numeric_limits<T>::infinity();
59  } else {
60  min = std::numeric_limits<T>::max();
61  max = std::numeric_limits<T>::lowest();
62  }
63  // Real mean = 0.0;
64  // Real mid = 0.0;
65  // must be Real because otherwise gives out-of-range values for signed types
66  Real range = 0;
67  T previous = data[0];
68  bool already_sorted = true;
69  for (auto datum : data) {
70  // mean += datum;
71  if (datum < min) {
72  min = datum;
73  }
74  // NOTE: >= to preserve stable sorting, so last max value gets put at end
75  /*
76  * Not actually an issue for this implementation because it only deals
77  * with primitives, however if extended to handle general-purpose types
78  * (using some casting), this will matter.
79  */
80  if (datum >= max) {
81  max = datum;
82  }
83  if (datum < previous) {
84  already_sorted = false;
85  }
86  previous = datum;
87  }
88  // short cut for already sorted
89  if (already_sorted) {
90  return;
91  }
92  // short cut for size 2
93  if (data.size() == 2) {
94  data[0] = min;
95  data[data.size() - 1] = max;
96  return;
97  }
98  if constexpr (std::is_floating_point<T>::value) {
99  if (min == -std::numeric_limits<T>::infinity()) {
100  min = std::numeric_limits<T>::lowest();
101  }
102  if (max == +std::numeric_limits<T>::infinity()) {
103  max = std::numeric_limits<T>::max();
104  }
105  }
106  // mean /= size;
107  // mid = (min + max) / 2.0;
108  range = (Real)max - (Real)min;
109  // temporary storage for sorting -- vector of sub-vectors to store partial sorts
110  std::vector<std::vector<T>> sorts(data.size() + 2);
111  for (auto n : data) {
112  if constexpr (std::is_floating_point<T>::value) {
113  if (n == -std::numeric_limits<T>::infinity()) {
114  sorts[0].push_back(n);
115  continue;
116  } else if (n == +std::numeric_limits<T>::infinity()) {
117  sorts[sorts.size() - 1].push_back(n);
118  continue;
119  }
120  }
121  // calculated sort position
122  Real raw_pos = std::ceil((((Real)n - min) / range) * (size - 1));
123  std::size_t pos = std::isnan(raw_pos) ? 1u : (std::size_t)raw_pos;
124  if (raw_pos < 0) {
125  pos = 0;
126  } else if (raw_pos > (sorts.size() - 1)) {
127  pos = sorts.size() - 1;
128  }
129  pos += 1;
130  sorts[pos].push_back(n);
131  }
132  // pull data out of sorted buckets, recursively sorting each before pulling
133  std::size_t i = 0;
134  for (auto& bucket : sorts) {
135  // recursively sort any sort buckets that are larger than 1
136  if (bucket.size() > 1) {
137  sort<T, std::dynamic_extent, Real>(bucket);
138  }
139  for (T datum : bucket) {
140  data[i] = datum;
141  i++;
142  }
143  }
144  return;
145  }
146 }
147 
148 #endif // include guard
Definition: tr-sort.hpp:27
void sort(std::span< T, Extent > data)
Stable sorts the input dating using the Transposition Sort sorting algorithm.
Definition: tr-sort.hpp:48