Skip to content

Commit f3ab1b9

Browse files
committed
Merge branch 'feature/straight-radix-sort'
of https://github.com/kraklo/algorithms-in-action-team29 into kraklo-feature/straight-radix-sort Need to add to menu etc
2 parents 14222e9 + 349e16f commit f3ab1b9

File tree

16 files changed

+18880
-17267
lines changed

16 files changed

+18880
-17267
lines changed

package-lock.json

Lines changed: 18218 additions & 17062 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"start:win32": "SET NODE_OPTIONS=--openssl-legacy-provider && react-scripts start",
1616
"test": "react-scripts test",
1717
"test-msdrs": "npm test -- ./src/algorithms/controllers/MSDRadixSort.test.js",
18+
"test-srs": "npm test -- ./src/algorithms/controllers/straightRadixSort.test.js",
1819
"test-uf": "npm test -- ./src/algorithms/controllers/unionFind.test.js",
1920
"test-234t": "npm test -- ./src/algorithms/controllers/TTFTree.test.js",
2021
"test-avl": "npm test -- ./src/algorithms/controllers/AVLTree.test.js",
@@ -67,6 +68,7 @@
6768
"@testing-library/react": "^12.1.2",
6869
"@testing-library/react-hooks": "^8.0.1",
6970
"@testing-library/user-event": "^14.4.3",
71+
"chai": "^5.1.1",
7072
"denque": "^2.0.1",
7173
"framer-motion": "^4.0.0",
7274
"lodash": "^4.17.21",

src/algorithms/controllers/collapseChunkPlugin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// below, otherwise hooks into what happens when blocks are expanded or
88
// contracted are not enabled.
99
const importsThis = ['quickSort', 'quickSortM3', 'msort_arr_td',
10-
'transitiveClosure', 'heapSort', 'msort_lista_td'];
10+
'transitiveClosure', 'heapSort', 'msort_lista_td', 'radixSortStraight'];
1111

1212
// eslint-disable-next-line import/no-cycle
1313
// See also accompanying mods/hooks in src/context/GlobalState.js and
@@ -40,7 +40,7 @@ export function areExpanded(blocks) {
4040
const alg_name = algorithm.id.name;
4141
const { bookmark, pseudocode, collapse } = algorithm;
4242
return blocks.reduce((acc, curr) =>
43-
(acc && collapse[alg_name].sort[curr]), true);
43+
(acc && collapse[alg_name].sort[curr]), true);
4444
}
4545

4646
// Trigger refresh of display when code is expanded/collapsed.
@@ -54,6 +54,7 @@ export function areExpanded(blocks) {
5454
export function onCollapseChange(chunker) {
5555
const algorithm = getGlobalAlgorithm();
5656
const alg_name = algorithm.id.name;
57+
console.log(alg_name);
5758
if (!importsThis.includes(alg_name)) return;
5859
chunker.refresh();
5960
}

src/algorithms/controllers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export { default as quickSort } from './quickSort';
55
export { default as quickSortM3 } from './quickSortM3';
66
export { default as msort_arr_td } from './msort_arr_td';
77
export { default as MSDRadixSort } from './MSDRadixSort';
8+
export { default as straightRadixSort } from './straightRadixSort';
89
export { default as msort_lista_td } from './msort_lista_td';
910
export { default as transitiveClosure } from './transitiveClosure';
1011
export { default as bruteForceStringSearch } from './bruteForceStringSearch';
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
import ArrayTracer from '../../components/DataStructures/Array/Array1DTracer';
2+
import MaskTracer from '../../components/DataStructures/Mask/MaskTracer';
3+
import { areExpanded } from './collapseChunkPlugin';
4+
5+
const BITS = 2;
6+
7+
const SRS_BOOKMARKS = {
8+
radix_sort: 1,
9+
max_number: 2,
10+
counting_sort_for_loop: 3,
11+
counting_sort: 4,
12+
count_nums: 5,
13+
cumulative_sum: 6,
14+
populate_array: 7,
15+
populate_for_loop: 8,
16+
insert_into_array: 9,
17+
copy: 10,
18+
done: 11,
19+
add_to_count: 12,
20+
add_count_for_loop: 13,
21+
cum_sum_for_loop: 14,
22+
add_cum_sum: 15,
23+
};
24+
25+
const isCountExpanded = () => {
26+
return areExpanded(["Countingsort"]);
27+
};
28+
29+
const highlight = (array, index, isPrimaryColor = true) => {
30+
if (isPrimaryColor) {
31+
array.select(index);
32+
} else {
33+
array.patch(index);
34+
}
35+
};
36+
37+
const unhighlight = (array, index, isPrimaryColor = true) => {
38+
if (isPrimaryColor) {
39+
array.deselect(index);
40+
} else {
41+
array.depatch(index);
42+
}
43+
};
44+
45+
const updateMask = (vis, index, bits) => {
46+
const mask = ((1 << bits) - 1) << (index * bits);
47+
const indexes = [];
48+
49+
for (let i = 0; i < vis.mask.maxBits; i++) {
50+
if (bitsAtIndex(mask, i, 1) == 1) {
51+
indexes.push(i);
52+
}
53+
}
54+
55+
vis.mask.setMask(mask, indexes);
56+
};
57+
58+
const updateBinary = (vis, value) => {
59+
vis.mask.setBinary(value);
60+
};
61+
62+
const bitsAtIndex = (num, index, bits) => {
63+
return num >> (index * bits) & ((1 << bits) - 1);
64+
};
65+
66+
const setArray = (visArray, array) => {
67+
visArray.set(array, 'straightRadixSort');
68+
};
69+
70+
export default {
71+
initVisualisers,
72+
73+
/**
74+
*
75+
* @param {object} chunker
76+
* @param {array} nodes array of numbers needs to be sorted
77+
*/
78+
run(chunker, { nodes }) {
79+
let A = [...nodes];
80+
const n = A.length;
81+
82+
const countingSort = (A, k, n, bits) => {
83+
const count = Array.apply(null, Array(1 << bits)).map(() => 0);
84+
let lastBit = -1;
85+
86+
chunker.add(SRS_BOOKMARKS.count_nums);
87+
88+
for (let i = 0; i < n; i++) {
89+
chunker.add(SRS_BOOKMARKS.add_count_for_loop,
90+
(vis, i, lastBit) => {
91+
if (i !== 0) {
92+
unhighlight(vis.array, i - 1);
93+
}
94+
95+
if (lastBit !== -1 && isCountExpanded()) {
96+
unhighlight(vis.countArray, lastBit);
97+
}
98+
99+
highlight(vis.array, i);
100+
updateBinary(vis, A[i]);
101+
},
102+
[i, lastBit]
103+
);
104+
105+
const bit = bitsAtIndex(A[i], k, bits);
106+
count[bit]++;
107+
108+
chunker.add(SRS_BOOKMARKS.add_to_count,
109+
(vis, count) => {
110+
if (isCountExpanded()) {
111+
setArray(vis.countArray, count);
112+
highlight(vis.countArray, bit);
113+
}
114+
},
115+
[count]
116+
);
117+
118+
lastBit = bit;
119+
}
120+
121+
chunker.add(SRS_BOOKMARKS.cumulative_sum,
122+
(vis, n, lastBit) => {
123+
unhighlight(vis.array, n - 1);
124+
125+
if (isCountExpanded()) {
126+
unhighlight(vis.countArray, lastBit);
127+
}
128+
},
129+
[n, lastBit]
130+
);
131+
132+
for (let i = 1; i < count.length; i++) {
133+
chunker.add(SRS_BOOKMARKS.cum_sum_for_loop,
134+
(vis, i) => {
135+
if (i === 1 && isCountExpanded()) {
136+
highlight(vis.countArray, 0);
137+
}
138+
},
139+
[i]
140+
);
141+
142+
count[i] += count[i - 1];
143+
144+
chunker.add(SRS_BOOKMARKS.add_cum_sum,
145+
(vis, count, i) => {
146+
if (isCountExpanded()) {
147+
setArray(vis.countArray, count);
148+
highlight(vis.countArray, i);
149+
}
150+
},
151+
[count, i]
152+
)
153+
}
154+
155+
const sortedA = Array.apply(null, Array(n)).map(() => 0);
156+
157+
chunker.add(SRS_BOOKMARKS.populate_array,
158+
(vis, countLength) => {
159+
if (isCountExpanded()) {
160+
unhighlight(vis.countArray, countLength - 1);
161+
}
162+
},
163+
[count.length]
164+
);
165+
166+
chunker.add(SRS_BOOKMARKS.populate_for_loop);
167+
168+
let bit;
169+
170+
for (let i = n - 1; i >= 0; i--) {
171+
const num = A[i];
172+
bit = bitsAtIndex(num, k, bits);
173+
count[bit]--;
174+
sortedA[count[bit]] = num;
175+
chunker.add(SRS_BOOKMARKS.insert_into_array,
176+
(vis, num, i, bit, count, sortedA) => {
177+
if (i !== n - 1) {
178+
unhighlight(vis.array, i + 1);
179+
}
180+
181+
if (isCountExpanded()) {
182+
setArray(vis.countArray, count);
183+
setArray(vis.tempArray, sortedA);
184+
highlight(vis.countArray, bit);
185+
highlight(vis.tempArray, count[bit]);
186+
}
187+
188+
updateBinary(vis, num);
189+
highlight(vis.array, i);
190+
},
191+
[num, i, bit, count, sortedA]
192+
);
193+
}
194+
195+
chunker.add(SRS_BOOKMARKS.copy,
196+
(vis, array, n, countLength) => {
197+
setArray(vis.array, array);
198+
199+
if (isCountExpanded()) {
200+
setArray(vis.tempArray, Array.apply(null, Array(n)).map(() => undefined));
201+
setArray(vis.countArray, Array.apply(null, Array(countLength)).map(() => undefined));
202+
}
203+
},
204+
[sortedA, n, count.length]
205+
);
206+
207+
return sortedA;
208+
};
209+
210+
let maxNumber = Math.max(...A);
211+
let maxBit = -1;
212+
213+
while (maxNumber > 0) {
214+
maxNumber = Math.floor(maxNumber / 2);
215+
maxBit++;
216+
}
217+
218+
let bits = 1;
219+
220+
while (bits < maxBit) {
221+
bits *= 2;
222+
}
223+
224+
chunker.add(SRS_BOOKMARKS.radix_sort,
225+
(vis, array) => {
226+
setArray(vis.array, array);
227+
228+
if (isCountExpanded()) {
229+
setArray(vis.countArray, Array.apply(null, Array(1 << BITS)).map(() => undefined));
230+
setArray(vis.tempArray, Array.apply(null, Array(n)).map(() => undefined));
231+
}
232+
},
233+
[nodes]
234+
);
235+
236+
chunker.add(SRS_BOOKMARKS.max_number,
237+
(vis, bits) => {
238+
vis.mask.setMaxBits(bits);
239+
},
240+
[bits]
241+
);
242+
243+
for (let k = 0; k < bits / BITS; k++) {
244+
chunker.add(SRS_BOOKMARKS.counting_sort_for_loop,
245+
vis => {
246+
updateMask(vis, k, BITS);
247+
}
248+
);
249+
250+
A = countingSort(A, k, n, BITS);
251+
252+
chunker.add(SRS_BOOKMARKS.counting_sort);
253+
}
254+
255+
chunker.add(SRS_BOOKMARKS.done,
256+
vis => {
257+
for (let i = 0; i < n; i++) {
258+
vis.array.sorted(i);
259+
}
260+
}
261+
);
262+
263+
return A;
264+
}
265+
};
266+
267+
268+
export function initVisualisers() {
269+
if (isCountExpanded()) {
270+
return {
271+
mask: {
272+
instance: new MaskTracer('mask', null, 'Mask'),
273+
order: 0,
274+
},
275+
array: {
276+
instance: new ArrayTracer('array', null, 'Array view', { arrayItemMagnitudes: false }),
277+
order: 1,
278+
},
279+
countArray: {
280+
instance: new ArrayTracer('countArray', null, 'Count array', { arrayItemMagnitudes: false }),
281+
order: 1,
282+
},
283+
tempArray: {
284+
instance: new ArrayTracer('tempArray', null, 'Temp array', { arrayItemMagnitudes: false }),
285+
order: 1,
286+
},
287+
};
288+
} else {
289+
return {
290+
mask: {
291+
instance: new MaskTracer('mask', null, 'Mask'),
292+
order: 0,
293+
},
294+
array: {
295+
instance: new ArrayTracer('array', null, 'Array view', { arrayItemMagnitudes: true }),
296+
order: 1,
297+
},
298+
};
299+
}
300+
}

0 commit comments

Comments
 (0)