1 /*******************************************************************************
2 * src/SortArray.cpp
3 *
4 * SortArray represents a simple array, which is displayed by WSortView to the
5 * user is real-time.
6 *
7 *******************************************************************************
8 * Copyright (C) 2014 Timo Bingmann <tb@panthema.net>
9 *
10 * This program is free software: you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation, either version 3 of the License, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License along with
21 * this program. If not, see <http://www.gnu.org/licenses/>.
22 ******************************************************************************/
23
24 #include "SortArray.h"
25 #include "SortAlgo.h"
26
27 #include <algorithm>
28
29 extern void SoundAccess(size_t i);
30
31 // *****************************************************************************
32 // *** Comparisons of ArrayItems
33
34 size_t g_compare_count = 0;
35
36 size_t g_access_count = 0;
37
OnAccess(const ArrayItem & a)38 void ArrayItem::OnAccess(const ArrayItem& a)
39 {
40 SoundAccess(a.get_direct());
41 }
42
OnComparison(const ArrayItem & a,const ArrayItem & b)43 void ArrayItem::OnComparison(const ArrayItem& a, const ArrayItem& b)
44 {
45 ++g_compare_count;
46
47 SoundAccess(a.get_direct());
48 SoundAccess(b.get_direct());
49 }
50
51 // *****************************************************************************
52 // *** SortArray
53
SortArray()54 SortArray::SortArray()
55 : m_calc_inversions(false),
56 m_delay(NULL)
57 {
58 }
59
OnAlgoLaunch(const AlgoEntry & ae)60 void SortArray::OnAlgoLaunch(const AlgoEntry& ae)
61 {
62 if (size() <= ae.inversion_count_limit)
63 {
64 m_calc_inversions = true;
65 RecalcInversions();
66 }
67 else
68 {
69 m_calc_inversions = false;
70 m_inversions = -1;
71 }
72 }
73
ResetArray(size_t size)74 void SortArray::ResetArray(size_t size)
75 {
76 m_array.resize(size, ArrayItem(0));
77 m_mark.resize(size);
78 }
79
FinishFill()80 void SortArray::FinishFill()
81 {
82 ASSERT(m_array.size() > 0);
83
84 // calculate max value in array
85 m_array_max = m_array[0].get_direct();
86 for (size_t i = 1; i < size(); ++i)
87 {
88 if (m_array_max < m_array[i].get_direct())
89 m_array_max = m_array[i].get_direct();
90 }
91
92 // reset access markers
93 unmark_all();
94 unwatch_all();
95
96 // reset counters and info
97 m_is_sorted = false;
98 g_access_count = 0;
99 g_compare_count = 0;
100 m_calc_inversions = true;
101
102 RecalcInversions();
103 }
104
FillInputlist(wxArrayString & list)105 void SortArray::FillInputlist(wxArrayString& list)
106 {
107 list.Add(_("Random Shuffle"));
108 list.Add(_("Ascending"));
109 list.Add(_("Descending"));
110 list.Add(_("Shuffled Cubic"));
111 list.Add(_("Shuffled Quintic"));
112 list.Add(_("Shuffled n-2 Equal"));
113 }
114
FillData(unsigned int schema,size_t arraysize)115 void SortArray::FillData(unsigned int schema, size_t arraysize)
116 {
117 if (arraysize == 0) arraysize = 1;
118
119 ResetArray(arraysize);
120
121 if (schema == 0) // Shuffle of [1,n]
122 {
123 for (size_t i = 0; i < m_array.size(); ++i)
124 m_array[i] = ArrayItem(i+1);
125
126 std::random_shuffle(m_array.begin(), m_array.end());
127 }
128 else if (schema == 1) // Ascending [1,n]
129 {
130 for (size_t i = 0; i < m_array.size(); ++i)
131 m_array[i] = ArrayItem(i+1);
132 }
133 else if (schema == 2) // Descending [1,n]
134 {
135 for (size_t i = 0; i < m_array.size(); ++i)
136 m_array[i] = ArrayItem(m_array.size() - i);
137 }
138 else if (schema == 3) // Cubic skew of [1,n]
139 {
140 for (size_t i = 0; i < m_array.size(); ++i)
141 {
142 // normalize to [-1,+1]
143 double x = (2.0 * (double)i / m_array.size()) - 1.0;
144 // calculate x^3
145 double v = x * x * x;
146 // normalize to array size
147 double w = (v + 1.0) / 2.0 * arraysize + 1;
148 // decrease resolution for more equal values
149 w /= 3.0;
150 m_array[i] = ArrayItem(w + 1);
151 }
152
153 std::random_shuffle(m_array.begin(), m_array.end());
154 }
155 else if (schema == 4) // Quintic skew of [1,n]
156 {
157 for (size_t i = 0; i < m_array.size(); ++i)
158 {
159 // normalize to [-1,+1]
160 double x = (2.0 * (double)i / m_array.size()) - 1.0;
161 // calculate x^5
162 double v = x * x * x * x * x;
163 // normalize to array size
164 double w = (v + 1.0) / 2.0 * arraysize + 1;
165 // decrease resolution for more equal values
166 w /= 3.0;
167 m_array[i] = ArrayItem(w + 1);
168 }
169
170 std::random_shuffle(m_array.begin(), m_array.end());
171 }
172 else if (schema == 5) // shuffled n-2 equal values in [1,n]
173 {
174 m_array[0] = ArrayItem(1);
175 for (size_t i = 1; i < m_array.size()-1; ++i)
176 {
177 m_array[i] = ArrayItem( arraysize / 2 + 1 );
178 }
179 m_array[m_array.size()-1] = ArrayItem(arraysize);
180
181 std::random_shuffle(m_array.begin(), m_array.end());
182 }
183 else // fallback
184 {
185 return FillData(0, arraysize);
186 }
187
188 FinishFill();
189 }
190
OnAccess()191 void SortArray::OnAccess()
192 {
193 ++g_access_count;
194
195 if (m_delay)
196 m_delay->OnAccess();
197 }
198
CheckSorted()199 bool SortArray::CheckSorted()
200 {
201 unmark_all();
202 // needed because iterator instrumentated algorithms may have changed the array
203 RecalcInversions();
204
205 ArrayItem prev = get_nocount(0);
206 mark(0);
207
208 bool is_sorted = true;
209
210 for (size_t i = 1; i < size(); ++i)
211 {
212 ArrayItem key = get_nocount(i);
213 g_compare_count--; // dont count the following comparison
214 if (!(prev <= key)) {
215 wxLogError(_T("Result of sorting algorithm is incorrect!"));
216 is_sorted = false;
217 break;
218 }
219 mark(i);
220 prev = key;
221 }
222
223 unmark_all();
224
225 return (m_is_sorted = is_sorted);
226 }
227
SetCalcInversions(bool on)228 void SortArray::SetCalcInversions(bool on)
229 {
230 // toggle boolean
231 m_calc_inversions = on;
232
233 if (!m_calc_inversions)
234 m_inversions = -1;
235 }
236
ToggleCalcInversions()237 void SortArray::ToggleCalcInversions()
238 {
239 // toggle boolean
240 SetCalcInversions(!m_calc_inversions);
241 }
242
RecalcInversions()243 void SortArray::RecalcInversions()
244 {
245 if (!m_calc_inversions) {
246 m_inversions = -1;
247 return;
248 }
249
250 unsigned int inversions = 0;
251
252 for (size_t i = 0; i < size(); ++i)
253 {
254 const ArrayItem& a = direct(i);
255
256 for (size_t j = i+1; j < size(); ++j)
257 {
258 const ArrayItem& b = direct(j);
259
260 if ( a.greater_direct(b) )
261 {
262 inversions++;
263 }
264 }
265 }
266
267 m_inversions = inversions;
268 }
269
UpdateInversions(size_t i,size_t j)270 void SortArray::UpdateInversions(size_t i, size_t j)
271 {
272 if (!m_calc_inversions) {
273 m_inversions = -1;
274 return;
275 }
276 if (m_inversions < 0) return RecalcInversions();
277
278 if (i == j) return;
279
280 unsigned int lo = i, hi = j;
281 if (lo > hi) std::swap(lo, hi);
282
283 const ArrayItem& ilo = m_array[lo];
284 const ArrayItem& ihi = m_array[hi];
285 int invdelta = 0;
286
287 for (size_t k = lo + 1; k < hi; ++k)
288 {
289 if (m_array[k].less_direct(ilo))
290 invdelta--;
291 if (m_array[k].greater_direct(ilo))
292 invdelta++;
293
294 if (m_array[k].less_direct(ihi))
295 invdelta++;
296 if (m_array[k].greater_direct(ihi))
297 invdelta--;
298 }
299
300 if (ilo.less_direct(ihi))
301 invdelta++;
302 if (ilo.greater_direct(ihi))
303 invdelta--;
304
305 m_inversions += invdelta;
306 }
307
GetRuns() const308 size_t SortArray::GetRuns() const
309 {
310 unsigned int runs = 1;
311
312 for (size_t i = 1; i < size(); ++i)
313 {
314 const ArrayItem& a = direct(i-1);
315 const ArrayItem& b = direct(i);
316
317 if ( a.greater_direct(b) )
318 {
319 runs++;
320 }
321 }
322
323 return runs;
324 }
325
InAccessList(ssize_t idx)326 short SortArray::InAccessList(ssize_t idx)
327 {
328 if (idx < 0) return -1;
329
330 signed color = -1;
331 signed priority = -1;
332
333 for (std::vector<Access>::iterator it = m_access_list.begin();
334 it != m_access_list.end(); )
335 {
336 if (it->index != (size_t)idx) {
337 ++it;
338 continue;
339 }
340
341 if (it->priority >= priority)
342 {
343 priority = it->priority;
344 color = it->color;
345 }
346
347 if (it->sustain == 0) {
348 if (it->index == m_access1.index ||
349 it->index == m_access2.index)
350 {
351 ++it;
352 }
353 else
354 {
355 it = m_access_list.erase(it);
356 }
357 }
358 else {
359 it->sustain--;
360 ++it;
361 }
362 }
363
364 return color;
365 }
366
InWatchList(ssize_t idx) const367 unsigned short SortArray::InWatchList(ssize_t idx) const
368 {
369 for (size_t i = 0; i < m_watch.size(); ++i)
370 {
371 if (m_watch[i].first == NULL) continue;
372
373 // compare watched value
374 if (*m_watch[i].first != idx) continue;
375
376 return m_watch[i].second;
377 }
378 return 0;
379 }
380
GetIndexColor(size_t idx)381 int SortArray::GetIndexColor(size_t idx)
382 {
383 int clr;
384
385 // select color
386 if (idx == m_access1.index)
387 {
388 clr = m_access1.color;
389 }
390 else if (idx == m_access2.index)
391 {
392 clr = m_access2.color;
393 }
394 else if ( (clr = InWatchList(idx)) != 0 )
395 {
396 // clr already set
397 }
398 else if (m_mark[idx] != 0)
399 {
400 clr = m_mark[idx];
401 }
402 else if ( (clr = InAccessList(idx)) >= 0 )
403 {
404 }
405 else
406 {
407 clr = 0;
408 }
409
410 return clr;
411 }
412
413 // *****************************************************************************
414