Skip to content

Commit 059fa08

Browse files
committed
straight radix sort poppers done
Some instructions fixed/improved
1 parent 88b5ff6 commit 059fa08

File tree

5 files changed

+105
-31
lines changed

5 files changed

+105
-31
lines changed

src/algorithms/controllers/straightRadixSort.js

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
import ArrayTracer from '../../components/DataStructures/Array/Array1DTracer';
33
import MaskTracer from '../../components/DataStructures/Mask/MaskTracer';
44
import { areExpanded } from './collapseChunkPlugin';
5+
import { createPopper } from '@popperjs/core';
56

6-
const BITS = 2;
7+
// radix must be a power of two; we use radix 4 here but code should work
8+
// with another radix except vis.mask.setAddBase4() would need to be
9+
// generalised and that call deleted if radix = 2
10+
const RADIX_BITS = 2;
11+
const RADIX = 1 << RADIX_BITS;
712

813
const SRS_BOOKMARKS = {
914
radix_sort: 1,
@@ -84,9 +89,31 @@ export default {
8489
run(chunker, { nodes }) {
8590
let A = [...nodes];
8691
const n = A.length;
92+
// Stuff for poppers, copied from MSDRadixSort.js - search for
93+
// POPPERS: in that code for more details, though it's done
94+
// slightly differently here:
95+
// The first time the first chunk is called, poppers are created
96+
// (after a delay - see MSDRadixSort.js). Subsequent times the
97+
// first chunk is called we reset the innerHTML so the contents
98+
// is correct (it may have changed during execution).
99+
// Similarly, when the temp array is copied back to A we update
100+
// the innerHTML.
101+
let floatingBoxes = new Array(n); // XXX popper instances (rename)
102+
let DELAY_POPPER_CREATE = 700;
103+
let DELAY_POPPER_RESET = 800;
104+
let DELAY_POPPER_UPDATE = 800;
105+
106+
let bits; // number of bits used (depends on max data value)
107+
108+
// poppers show binary plus whatever radix we use
109+
// XXX if radix === 2, best avoid duplication
110+
const popperContent = (n) => {
111+
return n.toString(2).padStart(bits, "0") + "<br>"
112+
+ n.toString(RADIX).padStart(bits/RADIX_BITS, "0");
113+
}
87114

88-
const countingSort = (A, k, n, bits) => {
89-
const count = Array.apply(null, Array(1 << bits)).map(() => 0);
115+
const countingSort = (A, k, n, radixBits) => {
116+
const count = Array.apply(null, Array(1 << radixBits)).map(() => 0);
90117
let lastBit = -1;
91118

92119
chunker.add(SRS_BOOKMARKS.zero_counts,
@@ -118,7 +145,7 @@ export default {
118145
[i, lastBit, count]
119146
);
120147

121-
const bit = bitsAtIndex(A[i], k, bits);
148+
const bit = bitsAtIndex(A[i], k, radixBits);
122149
count[bit]++;
123150

124151
chunker.add(SRS_BOOKMARKS.add_to_count,
@@ -216,7 +243,7 @@ export default {
216243
},
217244
[num, i, bit, count, sortedA]
218245
);
219-
bit = bitsAtIndex(num, k, bits);
246+
bit = bitsAtIndex(num, k, radixBits);
220247
count[bit]--;
221248
chunker.add(SRS_BOOKMARKS.dec_count,
222249
(vis, num, i, bit, count, sortedA) => {
@@ -242,62 +269,101 @@ export default {
242269
}
243270

244271
chunker.add(SRS_BOOKMARKS.copy,
245-
(vis, array, n, countLength) => {
272+
(vis, array, n, countLength, bits) => {
246273
setArray(vis.array, array);
247274

248275
if (isCountExpanded()) {
249276
setArray(vis.tempArray, Array.apply(null, Array(n)).map(() => undefined));
250277
setArray(vis.countArray, Array.apply(null, Array(countLength)).map(() => undefined));
251278
}
279+
// update contents of all poppers
280+
setTimeout( () => {
281+
for (let idx = 0; idx < array.length; idx++) {
282+
const popper = document.getElementById('float_box_' + idx);
283+
popper.innerHTML = popperContent(array[idx]);
284+
}
285+
}, DELAY_POPPER_UPDATE);
252286
},
253-
[sortedA, n, count.length]
287+
[sortedA, n, count.length, bits]
254288
);
255289

256290
return sortedA;
257291
};
258292

259293
let maxNumber = Math.max(...A);
260-
let maxBit = -1;
294+
let savedMax = maxNumber;
295+
let maxBit = 0;
261296

262297
while (maxNumber > 0) {
263298
maxNumber = Math.floor(maxNumber / 2);
264299
maxBit++;
265300
}
266301

267-
let bits = 1;
268-
269-
while (bits < maxBit) {
270-
bits *= 2;
271-
}
302+
bits = maxBit + maxBit % RADIX_BITS; // bits is multiple of radix
303+
floatingBoxes.fill(null); // poppers: see MSDRadixSort.js
272304

273305
chunker.add(SRS_BOOKMARKS.radix_sort,
274-
(vis, array) => {
306+
(vis, array, bits) => {
307+
// XXX assumes radix 4
275308
vis.mask.setAddBase4(true); // add Base 4 display
276309
setArray(vis.array, array);
277310

278311
if (isCountExpanded()) {
279-
setArray(vis.countArray, Array.apply(null, Array(1 << BITS)).map(() => undefined));
312+
setArray(vis.countArray, Array.apply(null, Array(1 << RADIX_BITS)).map(() => undefined));
280313
setArray(vis.tempArray, Array.apply(null, Array(n)).map(() => undefined));
281314
}
315+
// create poppers or reset poppers if they already exist
316+
for (let idx = 0; idx < array.length; idx++) {
317+
if (floatingBoxes[idx] === null) {
318+
setTimeout( () => {
319+
const popper = document.getElementById('float_box_' + idx);
320+
const slot = document.getElementById('chain_' + idx);
321+
floatingBoxes[idx] = createPopper(slot, popper, {
322+
placement: "right-start",
323+
strategy: "fixed",
324+
modifiers: [
325+
{
326+
removeOnDestroy: true, // doesn't work well?
327+
name: 'preventOverflow',
328+
options: {
329+
// XXX popper_boundary not defined for 1D
330+
// array - maybe it should be??
331+
boundary: document.getElementById('popper_boundary'),
332+
},
333+
},
334+
]
335+
});
336+
popper.innerHTML = popperContent(array[idx]);
337+
}, DELAY_POPPER_CREATE);
338+
} else {
339+
setTimeout( () => {
340+
const popper = document.getElementById('float_box_' + idx);
341+
popper.innerHTML = popperContent(array[idx]);
342+
floatingBoxes[idx].forceUpdate();
343+
}, DELAY_POPPER_RESET)
344+
}
345+
}
282346
},
283-
[nodes]
347+
[nodes, bits]
284348
);
285349

286350
chunker.add(SRS_BOOKMARKS.max_number,
287-
(vis, bits) => {
351+
(vis, bits, max) => {
352+
// XXX could highlight max in array also?
288353
vis.mask.setMaxBits(bits);
354+
updateBinary(vis, max);
289355
},
290-
[bits]
356+
[bits, savedMax]
291357
);
292358

293-
for (let k = 0; k < bits / BITS; k++) {
359+
for (let k = 0; k < bits / RADIX_BITS; k++) {
294360
chunker.add(SRS_BOOKMARKS.counting_sort_for_loop,
295361
vis => {
296-
updateMask(vis, k, BITS);
362+
updateMask(vis, k, RADIX_BITS);
297363
}
298364
);
299365

300-
A = countingSort(A, k, n, BITS);
366+
A = countingSort(A, k, n, RADIX_BITS);
301367

302368
// chunker.add(SRS_BOOKMARKS.counting_sort);
303369
}

src/algorithms/instructions/index.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const KEY_BACK = 'BACK';
66
const KEY_FORWARD = 'FORWARD';
77
const KEY_SEARCH = 'SEARCH';
88
const KEY_PROGRESS = 'PROGRESS';
9-
const KEY_SORT = 'SORT';
9+
const KEY_SORT = 'RESET/SORT'; // XXX change more algs to RESET
1010
const KEY_LOAD = 'START';
1111
const KEY_FIND = 'FIND STRING';
1212
const KEY_UF_UNION = 'UNION';
@@ -98,10 +98,19 @@ allows you to pre-fill some of the table quickly.`,
9898
const sortInstructions = [{
9999
title: 'Sorting Numbers',
100100
content: [
101-
`Click on ${KEY_CODE} on the right panel`,
102-
'Enter a list of numbers in the sort parameter.',
103-
`Click on ${KEY_SORT} or hit return to load the data.`,
104-
PLAY_INSTRUCTIONS,
101+
`Click on ${KEY_CODE} on the right panel to show the code.`,
102+
PLAY_INSTRUCTIONS,
103+
`The list of numbers to be sorted can be edited; click on ${KEY_SORT} or hit return to load the new data.`,
104+
],
105+
}];
106+
107+
const radixSortInstructions = [{
108+
title: 'Sorting Numbers',
109+
content: [
110+
`Click on ${KEY_CODE} on the right panel to show the code.`,
111+
PLAY_INSTRUCTIONS,
112+
`The list of numbers to be sorted can be edited; click on ${KEY_SORT} or hit return to load the new data.`,
113+
'Hover the mouse over an element of array A to display the value in binary (and base 4 for straight radix sort).',
105114
],
106115
}];
107116

@@ -161,7 +170,7 @@ export const QSInstruction = sortInstructions;
161170
export const msort_arr_td = sortInstructions;
162171
export const msort_arr_bup = sortInstructions;
163172
export const msort_arr_nat = sortInstructions;
164-
export const RadixSortInstruction = sortInstructions;
173+
export const RadixSortInstruction = radixSortInstructions;
165174
export const msort_lista_td = sortInstructions;
166175
export const TCInstruction = graphInstructionsTC;
167176
export const Prims_oldInstruction = graphInstructions;

src/algorithms/parameters/MSDRadixSortParam.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
88
import { withAlgorithmParams } from './helpers/urlHelpers';
99
import '../../styles/Param.scss';
1010

11-
const DEFAULT_NODES = genRandNumList(10, 1, 100);
11+
const DEFAULT_NODES = genRandNumList(10, 1, 63); // limit bits by default
1212
const DEFAULT_MODE = 'sort';
1313
const MSD_RADIX_SORT = 'MSD Radix Sort';
1414
const MSDRS_SORT_EXAMPLE = 'Please follow the example provided: 0,1,2,3,4';

src/algorithms/parameters/StraightRadixSortParam.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
88
import { withAlgorithmParams } from './helpers/urlHelpers';
99
import '../../styles/Param.scss';
1010

11-
const DEFAULT_NODES = genRandNumList(10, 1, 100);
11+
const DEFAULT_NODES = genRandNumList(10, 1, 63); // limit bits by default
1212
const DEFAULT_MODE = 'sort';
1313
const Straight_RADIX_SORT = 'Straight Radix Sort';
1414
const MSDRS_SORT_EXAMPLE = 'Please follow the example provided: 0,1,2,3,4';

src/components/DataStructures/Array/Array1DRenderer/index.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ import styles from './Array1DRenderer.module.scss';
2727
import { classes } from '../../common/util';
2828
import { mode } from '../../../top/Settings';
2929
// Add your algo to this if you want to use the float box/popper
30-
// XXX add straight radix sort some time?
31-
const ALGOS_USING_FLOAT_BOX = ["MSDRadixSort"];
30+
const ALGOS_USING_FLOAT_BOX = ["MSDRadixSort", "straightRadixSort"];
3231

3332
let modename;
3433
function switchmode(modetype = mode()) {

0 commit comments

Comments
 (0)