Skip to content

Commit 4aa155f

Browse files
committed
Partition in REX++
1 parent 57e7c78 commit 4aa155f

File tree

4 files changed

+59
-30
lines changed

4 files changed

+59
-30
lines changed

src/algorithms/controllers/MSDRadixSort.js

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const MSD_BOOKMARKS = {
5454
partition_right: 305,
5555
swap_condition: 309,
5656
swap: 310,
57+
inc_dec: 'inc_dec',
5758
pre_sort_left: 400,
5859
sort_left: 401,
5960
pre_sort_right: 500,
@@ -159,7 +160,13 @@ export default {
159160
// where mid is undefined until after partition
160161
const finished_stack_frames = [];
161162
const real_stack = [];
162-
let leftCheck = false
163+
// refreshStack does lots of work with highlighting etc but is
164+
// called from other functions which are called from other
165+
// function and somewhere along the line one of the functions is
166+
// chunker.add. Often the arguments are not given explicitly -
167+
// it's a mess. We assign the current bookmark to whereAreWe for
168+
// now, to be used in refreshStack. Maybe worth a re-write XXX.
169+
let whereAreWe;
163170

164171
// ----------------------------------------------------------------------------------------------------------------------------
165172
// Define helper functions
@@ -169,14 +176,12 @@ export default {
169176
// This function is the only way information is cached and incremented properly in the while loop
170177
const partitionChunker = (bookmark, i, j, prev_i, prev_j, left, right, depth, arr, mask) => {
171178
assert(bookmark !== undefined); // helps catch bugs early, and trace them in stack
172-
const args_array = [real_stack, finished_stack_frames, i, j, prev_i, prev_j, left, right, depth, leftCheck, maxIndex, arr, mask]
179+
const args_array = [real_stack, finished_stack_frames, i, j, prev_i, prev_j, left, right, depth, whereAreWe, maxIndex, arr, mask]
173180
chunker.add(bookmark, refreshStack, args_array, depth)
174181
}
175182

176-
// we use a global flag in case we scan through the whole partition
177-
// and stop at the end without finding the mask bit we are looking
178-
// for
179-
const refreshStack = (vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, prev_i, prev_j, left, right, cur_depth, checkingLeft, maxIndex, arr, mask) => {
183+
// see comment above on whereAreWe
184+
const refreshStack = (vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, prev_i, prev_j, left, right, cur_depth, whereAreWe, maxIndex, arr, mask) => {
180185
// If we fall off the start/end of the array we just use the
181186
// first/last element and give the actual value of j/i
182187
let cur_i_too_high;
@@ -198,17 +203,13 @@ export default {
198203
assert(vis.array);
199204
assert(cur_real_stack && cur_finished_stack_frames);
200205

201-
vis.array.setStackDepth(cur_real_stack.length);
202-
vis.array.setStack(
203-
deriveStack(cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_depth)
204-
);
206+
// XXX This was getting very messy - colors depends a
207+
// lot on where we are and we had a bunch of tricky testing of
208+
// various vars to determine that. Now we use whereAreWe to
209+
// simplify some things at least.
205210

206-
// XXX This is getting very messy - (un)highlighting depends a
207-
// lot on where we are and we have a bunch of tricky testing of
208-
// various vars to determine that. Could pass in bookmark to
209-
// simplify some things at least??
210211
// Show the binary representation for the current index
211-
// plus (un)highlight appropriate element(s)
212+
// plus color appropriate element(s)
212213
updateMask(vis, mask) // only needed for start of recursive function
213214
if (maxIndex !== undefined) { // top level call to recursive fn
214215
unhighlight(vis, maxIndex)
@@ -222,8 +223,18 @@ export default {
222223
vis.array.selectColor(prev_j, partLColor)
223224
for (let k = cur_i; k <= right; k++)
224225
vis.array.deselect(k);
225-
} else if (checkingLeft) {
226+
} else if (whereAreWe === MSD_BOOKMARKS.partition_left) {
226227
// note i can fall off RHS of array...
228+
if (cur_i !== undefined && cur_i <= right ) {
229+
updateBinary(vis, arr[cur_i]);
230+
if ((arr[cur_i] >> mask & 1) === 1)
231+
vis.array.selectColor(cur_i, partRColor)
232+
else {
233+
vis.array.selectColor(cur_i, partLColor);
234+
cur_i++; // show incremented i XXX fix i_too_high
235+
}
236+
}
237+
/*
227238
if (prev_i !== undefined && prev_i !== cur_j) {
228239
let real_i = cur_i;
229240
if (cur_i === undefined)
@@ -235,7 +246,8 @@ export default {
235246
}
236247
if (arr && cur_i !== undefined)
237248
updateBinary(vis, arr[cur_i])
238-
} else {
249+
*/
250+
} else if (whereAreWe === MSD_BOOKMARKS.partition_right) {
239251
// note j can fall off LHS of array...
240252
if (prev_j !== undefined && prev_j !== cur_i)
241253
for (let k = prev_j; k >= cur_j && k >= cur_i; k--)
@@ -246,6 +258,11 @@ export default {
246258
updateBinary(vis, arr[cur_j])
247259
}
248260
}
261+
262+
vis.array.setStackDepth(cur_real_stack.length);
263+
vis.array.setStack(
264+
deriveStack(cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_depth)
265+
);
249266
if (left < A.length) // shouldn't happen with initial mask choice
250267
assignVariable(vis, VIS_VARIABLE_STRINGS.left, left);
251268
if (right >= 0) {
@@ -382,16 +399,18 @@ arr],
382399
prev_i = i; // save prev value for unhighlighting
383400
prev_j = j;
384401
// Build the left group until it reaches the mask (find the big element)
385-
leftCheck = true
402+
// leftCheck = true
403+
whereAreWe = MSD_BOOKMARKS.partition_left;
386404
while (i <= j && (arr[i] >> mask & 1) === 0) {
387-
// partitionChunkerWrapper(MSD_BOOKMARKS.partition_left)
405+
partitionChunkerWrapper(MSD_BOOKMARKS.partition_left)
388406
i++
389407
}
390408
partitionChunkerWrapper(MSD_BOOKMARKS.partition_left)
391409
// Build the right group until it fails the mask (find the small element)
392-
leftCheck = false
410+
// leftCheck = false
411+
whereAreWe = MSD_BOOKMARKS.partition_right;
393412
while (j > i && (arr[j] >> mask & 1) === 1) {
394-
// partitionChunkerWrapper(MSD_BOOKMARKS.partition_right)
413+
partitionChunkerWrapper(MSD_BOOKMARKS.partition_right)
395414
j--
396415
}
397416
partitionChunkerWrapper(MSD_BOOKMARKS.partition_right)
@@ -400,6 +419,9 @@ arr],
400419
if (i < j) {
401420
partitionChunkerWrapper(MSD_BOOKMARKS.swap_condition)
402421
swapAction(MSD_BOOKMARKS.swap, i, j)
422+
i++;
423+
j--;
424+
partitionChunkerWrapper(MSD_BOOKMARKS.inc_dec)
403425
} else {
404426
// about to return i from partition. We update the "mid" of
405427
// the partition on the stack here so it is displayed at the

src/algorithms/explanations/MSDRadixSortExp.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,16 @@ mask bit of each key:
4141
* Increment ```i``` until an element with a 1 as the mask bit is reached
4242
* Decrement ```j``` until an element with a 0 as the mask bit is reached
4343

44-
* If the two guards have not crossed, perform a swap to ensure that 0s are placed on the left and 1s on the right.
44+
* If the two indices have not met/crossed, perform a swap to ensure that 0s are placed on the left and 1s on the right.
4545

4646
## Complexity
4747
### Time Complexity
48-
* Partitioning takes```O(n)```, where ```n``` is the number elements in the
48+
* Partitioning takes ```O(n)```, where ```n``` is the number elements in the
4949
array.
50-
* If we *assume the number of bits is limited* the overall time complexity is: ```O(n)```
50+
* If we *assume the maximum number of digits is fixed* the overall time complexity is: ```O(n)```
5151
* Note that the best comparison-based sorting algorithms have ```O(n log n)```
5252
complexity, but the number of bits is typically related to ```log n```
53+
(otherwise there must be many duplicate keys)
5354
so radix sorts are not necessarily better.
5455

5556
### Space Complexity

src/algorithms/explanations/StraightRadixSortExp.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
## Introduction
66
Unlike most sorting algorithms, which are based on *comparison* of whole
77
keys, radix sorting is based on examining individual "digits" in the
8-
keys. For integers (used here) this could be decimal digits (base 10), bits (base 2) or and other
8+
keys. For integers (used here) this could be decimal digits (base 10), bits (base 2) or any other
99
base. Using bytes (base 256) has efficiency advantages but here we use base 4
1010
(digits 0-3) for illustration.
1111
Straight Radix Sort (also known as Least Significant Digit Radix Sort)
@@ -23,13 +23,17 @@ The ```Radixsort``` function begins by determining the maximum number of digits,
2323
in the data. This number defines how many iterations the algorithm will go through,
2424
starting from the least significant (right-most) digit moving toward the most
2525
significant (left-most). Here we use base 4 digits (0-3 or two bits)
26-
and show values in binary.
26+
and show values in decimal, base 4 (the most helpful in understanding
27+
the algorithm) and binary.
2728

2829
### 2. Outer Loop
2930
For each digit (scanning right to left), *Counting Sort* is performed on that
3031
digit. This leave the array sorted.
3132

3233
### 3. Counting Sort
34+
35+
Counting sort has four parts:
36+
3337
* Counting occurrences of each digit (00, 01, 10 and 11 in binary)
3438
* For each key in the array, the digit at the current position is extracted.
3539
* The algorithm counts how many times each digit occurs.
@@ -47,10 +51,11 @@ the keys sorted on the current digit, is copied back to the original array ```A`
4751

4852
## Complexity
4953
### Time Complexity
50-
* Each iteration uses ```Countingsort```, which requires ```O(n)```, where n is the number of elements.
51-
* If we *assume the number of digits is limited* the overall time complexity is: ```O(n)```
54+
* Each iteration uses ```Countingsort```, which takes ```O(n)``` time, where n is the number of elements.
55+
* If we *assume the maximum number of digits is fixed* the overall time complexity is: ```O(n)```
5256
* Note that the best comparison-based sorting algorithms have ```O(n log n)```
5357
complexity, but the number of digits is typically related to ```log n```
58+
(otherwise there must be many duplicate keys)
5459
so radix sorts are not necessarily better.
5560

5661
### Space Complexity

src/algorithms/pseudocode/MSDRadixSort.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ i,j <- left,right \\B 301
7676
stopping at "small" elements (with "0" as the mask bit).
7777
\\Expl}
7878
while i < j \\B 303
79-
\\Expl{ When the indices cross, all the large elements at the left of
79+
\\Expl{ When the indices meet/cross, all the large elements at the left of
8080
the array segment have been swapped with small elements from the
8181
right of the array segment. The coding here can be simplified
8282
if we use "break" or similar to exit from this loop.
@@ -95,13 +95,14 @@ while i < j \\B 303
9595
Note we do the tests before decrementing j.
9696
\\Expl}
9797
if i < j \\B 309
98-
\\Expl{ If the indices cross, we exit the loop.
98+
\\Expl{ If the indices meet/cross, we exit the loop.
9999
\\Expl}
100100
\\In{
101101
swap(A[i], A[j]) \\B 310
102102
\\Expl{ Swap the larger element (A[i]) with the smaller
103103
element (A[j]).
104104
\\Expl}
105+
Increment i and decrement j \\B inc_dec
105106
\\In}
106107
\\In}
107108
\\Code}

0 commit comments

Comments
 (0)