Skip to content

Commit

Permalink
straightRadixSort various improvements
Browse files Browse the repository at this point in the history
+ minor one for msort_arr_nat
  • Loading branch information
lee-naish committed Jan 27, 2025
1 parent afa551a commit dfa606a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 54 deletions.
103 changes: 76 additions & 27 deletions src/algorithms/controllers/straightRadixSort.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Some animation deleted, some added; could delete some commented out stuff
import ArrayTracer from '../../components/DataStructures/Array/Array1DTracer';
import MaskTracer from '../../components/DataStructures/Mask/MaskTracer';
import { areExpanded } from './collapseChunkPlugin';
Expand All @@ -8,10 +9,10 @@ const SRS_BOOKMARKS = {
radix_sort: 1,
max_number: 2,
counting_sort_for_loop: 3,
counting_sort: 4,
count_nums: 5,
cumulative_sum: 6,
populate_array: 7,
// counting_sort: 4, // no longer used
// count_nums: 5, // no longer used
// cumulative_sum: 6, // no longer used
// populate_array: 7, // no longer used
populate_for_loop: 8,
insert_into_array: 9,
copy: 10,
Expand All @@ -20,6 +21,9 @@ const SRS_BOOKMARKS = {
add_count_for_loop: 13,
cum_sum_for_loop: 14,
add_cum_sum: 15,
zero_counts: 16,
get_digit1: 17,
dec_count: 18,
};

const isCountExpanded = () => {
Expand Down Expand Up @@ -63,6 +67,8 @@ const bitsAtIndex = (num, index, bits) => {
return num >> (index * bits) & ((1 << bits) - 1);
};

// could check that isArray is defined and avoid some of the
// isCountExpanded() checks elsewhere
const setArray = (visArray, array) => {
visArray.set(array, 'straightRadixSort');
};
Expand All @@ -83,11 +89,21 @@ export default {
const count = Array.apply(null, Array(1 << bits)).map(() => 0);
let lastBit = -1;

chunker.add(SRS_BOOKMARKS.count_nums);
chunker.add(SRS_BOOKMARKS.zero_counts,
(vis, count) => {
if (isCountExpanded()) {
setArray(vis.countArray, count);
}
},
[count]
);

for (let i = 0; i < n; i++) {
chunker.add(SRS_BOOKMARKS.add_count_for_loop,
(vis, i, lastBit) => {
(vis, i, lastBit, count) => {
if (isCountExpanded()) {
setArray(vis.countArray, count);
}
if (i !== 0) {
unhighlight(vis.array, i - 1);
}
Expand All @@ -99,7 +115,7 @@ export default {
highlight(vis.array, i);
updateBinary(vis, A[i]);
},
[i, lastBit]
[i, lastBit, count]
);

const bit = bitsAtIndex(A[i], k, bits);
Expand All @@ -118,6 +134,7 @@ export default {
lastBit = bit;
}

/*
chunker.add(SRS_BOOKMARKS.cumulative_sum,
(vis, n, lastBit) => {
unhighlight(vis.array, n - 1);
Expand All @@ -128,15 +145,23 @@ export default {
},
[n, lastBit]
);
*/

for (let i = 1; i < count.length; i++) {
chunker.add(SRS_BOOKMARKS.cum_sum_for_loop,
(vis, i) => {
if (i === 1 && isCountExpanded()) {
highlight(vis.countArray, 0);
(vis, i, n, lastBit) => {
if (isCountExpanded()) {
if (i === 1) {
unhighlight(vis.array, n - 1);
} else
unhighlight(vis.countArray, i-1, false);
if (i === 1 && isCountExpanded()) {
unhighlight(vis.countArray, lastBit);
}
highlight(vis.countArray, i);
}
},
[i]
[i, n, lastBit]
);

count[i] += count[i - 1];
Expand All @@ -145,15 +170,16 @@ export default {
(vis, count, i) => {
if (isCountExpanded()) {
setArray(vis.countArray, count);
highlight(vis.countArray, i);
highlight(vis.countArray, i, false);
}
},
[count, i]
)
}

const sortedA = Array.apply(null, Array(n)).map(() => 0);
const sortedA = Array.apply(null, Array(n)).map(() => undefined);

/*
chunker.add(SRS_BOOKMARKS.populate_array,
(vis, countLength) => {
if (isCountExpanded()) {
Expand All @@ -162,31 +188,54 @@ export default {
},
[count.length]
);
*/

chunker.add(SRS_BOOKMARKS.populate_for_loop);
// chunker.add(SRS_BOOKMARKS.populate_for_loop);

let bit;

for (let i = n - 1; i >= 0; i--) {
const num = A[i];
chunker.add(SRS_BOOKMARKS.populate_for_loop,
(vis, num, i, bit, count, sortedA) => {
if (i === n - 1) {
if (isCountExpanded()) {
unhighlight(vis.countArray, count.length - 1, false);
}
} else {
unhighlight(vis.array, i + 1);
if (isCountExpanded()) {
setArray(vis.countArray, count);
setArray(vis.tempArray, sortedA);
unhighlight(vis.countArray, bit);
unhighlight(vis.tempArray, count[bit]);
}
}
updateBinary(vis, num);
highlight(vis.array, i);
},
[num, i, bit, count, sortedA]
);
bit = bitsAtIndex(num, k, bits);
count[bit]--;
chunker.add(SRS_BOOKMARKS.dec_count,
(vis, num, i, bit, count, sortedA) => {

if (isCountExpanded()) {
setArray(vis.countArray, count);
highlight(vis.countArray, bit);
}
},
[num, i, bit, count, sortedA]
);
sortedA[count[bit]] = num;
chunker.add(SRS_BOOKMARKS.insert_into_array,
(vis, num, i, bit, count, sortedA) => {
if (i !== n - 1) {
unhighlight(vis.array, i + 1);
}

if (isCountExpanded()) {
setArray(vis.countArray, count);
setArray(vis.tempArray, sortedA);
highlight(vis.countArray, bit);
highlight(vis.tempArray, count[bit]);
}

updateBinary(vis, num);
highlight(vis.array, i);
},
[num, i, bit, count, sortedA]
);
Expand Down Expand Up @@ -249,7 +298,7 @@ export default {

A = countingSort(A, k, n, BITS);

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

chunker.add(SRS_BOOKMARKS.done,
Expand All @@ -273,15 +322,15 @@ export function initVisualisers() {
order: 0,
},
array: {
instance: new ArrayTracer('array', null, 'Array view', { arrayItemMagnitudes: false }),
instance: new ArrayTracer('array', null, 'Array A', { arrayItemMagnitudes: false }),
order: 1,
},
countArray: {
instance: new ArrayTracer('countArray', null, 'Count array', { arrayItemMagnitudes: false }),
order: 1,
},
tempArray: {
instance: new ArrayTracer('tempArray', null, 'Temp array', { arrayItemMagnitudes: false }),
instance: new ArrayTracer('tempArray', null, 'Temp array B', { arrayItemMagnitudes: false }),
order: 1,
},
};
Expand All @@ -292,9 +341,9 @@ export function initVisualisers() {
order: 0,
},
array: {
instance: new ArrayTracer('array', null, 'Array view', { arrayItemMagnitudes: true }),
instance: new ArrayTracer('array', null, 'Array A', { arrayItemMagnitudes: true }),
order: 1,
},
};
}
}
}
2 changes: 1 addition & 1 deletion src/algorithms/pseudocode/msort_arr_nat.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ MergeAll
\\Expl{ We compute mid to get the longest sequence where A[left] <=
A[left+1] <= ... <= A[mid].
\\Expl}
find the second run, A[mid+1..right] it could be empty \\Ref SecondRun
find the second run, A[mid+1..right] (possibly empty) \\Ref SecondRun
\\Expl{ We compute right to get the longest sequence where A[mid+1] <=
A[mid+2] <= ... <= A[right]. If mid = size this will be empty.
\\Expl}
Expand Down
53 changes: 27 additions & 26 deletions src/algorithms/pseudocode/straightRadixSort.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ would be good for the counts array.
\\Code{
Main
Radixsort(A, n) // Sort array A[1]..A[n] in ascending order. \\B 1
Radixsort(A, n) // Sort array A[0]..A[n-1] in ascending order. \\B 1
\\Expl{ Note that all arrays start at index zero.
\\Expl}
Find maximum number of "digits" used in the data \\B 2
\\Expl{ This depends on the radix (base) we use to view the data.
Here we use radix 4 for illustration (the digits are 0-3 and use
two bits; we show the binary representation of the keys and the
mask used to extract the current digit).
We could use radix 10 (decimal digits), radix 2
(binary) or anything else. Here we use radix 4 for illustration
(the digits are 0-3 and use two bits). Radix 256 (one byte) is a
better choice in practice and we can set the maximum to be the
(binary) or anything else. Radix 256 (one byte) is a
good choice in practice and we can set the maximum to be the
word size rather than scanning all the input data as we do here.
\\Expl}
Expand All @@ -48,36 +52,36 @@ Radixsort(A, n) // Sort array A[1]..A[n] in ascending order. \\B 1
\\Code{
Countingsort
// Countingsort(A, k, n) \\B 4
// Count number of 1s and 0s in B
Array C <- counts of each kth digit value \\Ref CountNums
\\Expl{ We count the number of occurrences of each digit value (0-3
here) in the kth digits of the data.
Array Count <- counts of each kth digit value \\Ref CountNums
\\Expl{ We count the number of occurrences of each digit value (here 0-3
or binary 00-11) in the kth digits of the data.
\\Expl}
Cumulatively sum digit value counts \\Ref CumSum
\\Expl{ For each digit value, we compute the count for that digit value
plus all smaller digit values. This allows us to determine where the
last occurrence of each digit value will appear in the sorted array.
last occurrence of each digit value will appear in the sorted array
(the counts are one greater than the index because we start at index 0).
\\Expl}
Populate temporary array B with sorted numbers \\Ref Populate
Array B <- sorted numbers \\Ref Populate
\\Expl{ We copy the data to temporary array B, using the digit
value counts to determine where each element is copied to.
value counts to determine where each element is copied to, so the result
is sorted on this digit.
\\Expl}
Copy B back to A \\B 10
\\Expl{ Array A is now sorted on digit k and all smaller digits
(because the smaller digits were sorted previously and counting
\\Expl{ Array A is now sorted on digit k and all less significant digits
(because the less significant digits were sorted previously and counting
sort is stable).
\\Expl}
\\Code}
\\Code{
CountNums
// Put counts of each kth digit value in array C \\B 5
initialise array C to all zeros \\B 16
initialise array Count to all zeros \\B 16
for num in A \\B 13
\\In{
digit <- kth digit value in num \\B 17
\\Expl{ To extract the kth digit we can use div and mod operations.
\\Expl{ The digit is the two highlighted bits in the binary representation.
To extract the kth digit we can use div and mod operations.
If the radix is a power of two we can use bit-wise operations
(right shift and bit-wise and) instead.
\\Expl}
Expand All @@ -86,35 +90,32 @@ for num in A \\B 13
highlighted, and the digit value 0-3 (maybe the latter can be done
by just highlighting B[digit] instead).
\\Note}
C[digit] <- C[digit]+1 \\B 12
Count[digit] <- Count[digit]+1 \\B 12
\\In}
\\Code}
\\Code{
CumSum
// Cumulatively sum counts \\B 6
\\Note{ Best remove this comment line and move bookmark
\\Note}
for i = 1 to maximum digit value \\B 14
\\Expl{ We must scan left to right. The count for digit 0 remains
unchanged.
\\Expl}
\\In{
B[i] = B[i-1] + B[i] \\B 15
Count[i] = Count[i-1] + Count[i] \\B 15
\\In}
\\Code}
\\Code{
Populate
// Populate new array C with sorted numbers \\B 7
for each num in A in reverse order \\B 8
\\Expl{ We go from right to left so that we preserve the order of numbers
with the same digit.
This is CRUCIAL in radix sort as the counting sort MUST be stable.
\\Expl}
\\In{
digit <- kth digit value in num \\B 19
\\Expl{ To extract the kth digit value we can use div and mod operations.
\\Expl{ The digit is the two highlighted bits in the binary representation.
To extract the kth digit we can use div and mod operations.
If the radix is a power of two we can use bit-wise operations
(right shift and bit-wise and) instead.
\\Expl}
Expand All @@ -123,8 +124,8 @@ for each num in A in reverse order \\B 8
highlighted, and the digit value 0-3 (maybe the latter can be done
by just highlighting B[digit] instead).
\\Note}
B[digit] = B[digit]-1 \\B 18
C[B[digit]] = num \\B 9
Count[digit] = Count[digit]-1 \\B 18
B[Count[digit]] = num \\B 9
\\In}
\\Code}
Expand Down

0 comments on commit dfa606a

Please sign in to comment.