Skip to content

Commit 57e7c78

Browse files
committed
QS + REX colors + fixes mostly
Some corner cases fixed. SRS minor improvements
1 parent c995c35 commit 57e7c78

File tree

12 files changed

+148
-70
lines changed

12 files changed

+148
-70
lines changed

src/algorithms/controllers/MSDRadixSort.js

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const VIS_VARIABLE_STRINGS = {
3737
i_gt_n: 'i==n+1',
3838
j_eq_0: 'j==0',
3939
left: 'left',
40-
right: 'right'
40+
right: 'right',
41+
right_eq_0: 'right==0'
4142
};
4243

4344
const MSD_BOOKMARKS = {
@@ -172,6 +173,9 @@ export default {
172173
chunker.add(bookmark, refreshStack, args_array, depth)
173174
}
174175

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
175179
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) => {
176180
// If we fall off the start/end of the array we just use the
177181
// first/last element and give the actual value of j/i
@@ -194,21 +198,6 @@ export default {
194198
assert(vis.array);
195199
assert(cur_real_stack && cur_finished_stack_frames);
196200

197-
// conditions for i,j display moved elsewhere
198-
/*
199-
if (!isPartitionExpanded()) {
200-
// j should not show up in vis if partition is collapsed
201-
cur_j = undefined;
202-
cur_j_too_low = undefined;
203-
}
204-
205-
if (!isPartitionExpanded() && !isRecursionExpanded()) {
206-
// i should not show up in vis if partition + recursion is collapsed
207-
cur_i = undefined;
208-
cur_i_too_high = undefined;
209-
}
210-
*/
211-
212201
vis.array.setStackDepth(cur_real_stack.length);
213202
vis.array.setStack(
214203
deriveStack(cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_depth)
@@ -225,11 +214,7 @@ export default {
225214
unhighlight(vis, maxIndex)
226215
updateBinary(vis, 0)
227216
}
228-
if (cur_i == left && cur_j === right && prev_i === undefined) {
229-
// init, before partition
230-
highlight(vis, cur_i)
231-
highlight(vis, cur_j)
232-
} else if (cur_i !== undefined && tmp_j === undefined && prev_i !== undefined) {
217+
if (cur_i !== undefined && tmp_j === undefined && prev_i !== undefined) {
233218
// just before first recursive call
234219
if (i <= right)
235220
vis.array.selectColor(prev_i, partRColor)
@@ -238,29 +223,38 @@ export default {
238223
for (let k = cur_i; k <= right; k++)
239224
vis.array.deselect(k);
240225
} else if (checkingLeft) {
241-
if (prev_i !== undefined && prev_i !== cur_j)
242-
for (let k = prev_i; k < cur_i && k <= right; k++)
226+
// note i can fall off RHS of array...
227+
if (prev_i !== undefined && prev_i !== cur_j) {
228+
let real_i = cur_i;
229+
if (cur_i === undefined)
230+
real_i = right + 1;
231+
for (let k = prev_i; k < real_i && k <= right; k++)
243232
vis.array.selectColor(k, partLColor)
244-
if (cur_i < cur_j)
245-
highlight(vis, cur_i)
246-
else if (cur_i <= right)
233+
if (cur_i !== undefined && cur_i <= right && (arr[cur_i] >> mask & 1) === 1)
247234
vis.array.selectColor(cur_i, partRColor)
235+
}
248236
if (arr && cur_i !== undefined)
249237
updateBinary(vis, arr[cur_i])
250238
} else {
239+
// note j can fall off LHS of array...
251240
if (prev_j !== undefined && prev_j !== cur_i)
252241
for (let k = prev_j; k >= cur_j && k >= cur_i; k--)
253242
vis.array.selectColor(k, partRColor)
254-
if (cur_j !== undefined && cur_j > cur_i) { // might have fallen off array
255-
highlight(vis, cur_j);
243+
if (prev_j !== undefined && cur_j !== undefined && cur_j > cur_i) {
244+
vis.array.selectColor(cur_j, partLColor);
256245
// XXX probably best avoid updateBinary at swap
257246
updateBinary(vis, arr[cur_j])
258247
}
259248
}
260-
if (left < A.length)
249+
if (left < A.length) // shouldn't happen with initial mask choice
261250
assignVariable(vis, VIS_VARIABLE_STRINGS.left, left);
262-
if (right >= 0)
251+
if (right >= 0) {
263252
assignVariable(vis, VIS_VARIABLE_STRINGS.right, right);
253+
assignVariable(vis, VIS_VARIABLE_STRINGS.right_eq_0, undefined);
254+
} else {
255+
assignVariable(vis, VIS_VARIABLE_STRINGS.right, undefined);
256+
assignVariable(vis, VIS_VARIABLE_STRINGS.right_eq_0, 0);
257+
}
264258
if (isPartitionExpanded() || isRecursionExpanded()) {
265259
assignVariable(vis, VIS_VARIABLE_STRINGS.i_left_index, cur_i);
266260
assignVariable(vis, VIS_VARIABLE_STRINGS.i_gt_n, cur_i_too_high);
@@ -384,19 +378,19 @@ arr],
384378

385379
partitionChunkerWrapper(MSD_BOOKMARKS.set_i)
386380
// partitionChunkerWrapper(MSD_BOOKMARKS.set_j)
387-
while (i <= j) {
381+
while (i < j) {
388382
prev_i = i; // save prev value for unhighlighting
389383
prev_j = j;
390384
// Build the left group until it reaches the mask (find the big element)
391385
leftCheck = true
392-
while (i <= right && ((arr[i] >> mask & 1)) === 0) {
386+
while (i <= j && (arr[i] >> mask & 1) === 0) {
393387
// partitionChunkerWrapper(MSD_BOOKMARKS.partition_left)
394388
i++
395389
}
396390
partitionChunkerWrapper(MSD_BOOKMARKS.partition_left)
397391
// Build the right group until it fails the mask (find the small element)
398392
leftCheck = false
399-
while (j >= left && ((arr[j] >> mask & 1)) === 1) {
393+
while (j > i && (arr[j] >> mask & 1) === 1) {
400394
// partitionChunkerWrapper(MSD_BOOKMARKS.partition_right)
401395
j--
402396
}

src/algorithms/controllers/quickSort_shared.js

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ import {
2828
areExpanded,
2929
} from './collapseChunkPlugin';
3030

31+
import {colors} from '../../components/DataStructures/colors';
32+
const partLColor = colors.peach;
33+
const partRColor = colors.sky;
34+
const pivotColor = colors.leaf;
35+
const sortedColor = colors.stone;
36+
const highlightColor = colors.apple; // was for i,j in partition,...
37+
38+
3139
export function isPartitionExpanded() {
3240
return areExpanded(['Partition']);
3341
}
@@ -85,6 +93,7 @@ const QS_BOOKMARKS = {
8593
MEDIAN3_set_pivot_to_value_at_array_indx_right_minus_1: 5,
8694
SHARED_while_i_less_j: 6,
8795
SHARED_incri_i_until_array_index_i_greater_eq_pivot: 7,
96+
SHARED_incri_j_until: 7, // shortened name
8897
SHARED_decri_j_until: 8, // shortened name
8998
SHARED_if_j_greater_i: 9,
9099
SHARED_swap_array_i_j_vals: 10,
@@ -354,12 +363,15 @@ export function run_QS(is_qs_median_of_3) {
354363
[a[n1], a[n2]] = [a[n2], a[n1]]
355364

356365
chunker.add(bookmark,
357-
(vis, _n1, _n2, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
366+
(vis, _n1, _n2, cur_real_stack, cur_finished_stack_frames,
367+
cur_i, cur_j, cur_pivot_index, cur_depth, bm) => {
358368

359369
vis.array.swapElements(_n1, _n2);
360-
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth)
370+
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth);
371+
if (bm == QS_BOOKMARKS.SHARED_swap_pivot_into_position)
372+
vis.array.selectColor(_n1, sortedColor);
361373
},
362-
[n1, n2, real_stack, finished_stack_frames, i, j, pivot_index, depth],
374+
[n1, n2, real_stack, finished_stack_frames, i, j, pivot_index, depth, bookmark],
363375
depth);
364376
}
365377

@@ -387,15 +399,33 @@ export function run_QS(is_qs_median_of_3) {
387399

388400
const mid = Math.floor((left + right) / 2);
389401

402+
// here we color the three potential pivot elements according
403+
// to their final positions after swapping, so the colors
404+
// stick to the elements and will be in the right order after
405+
// swaps. We duplicate the if-then-elses but just change
406+
// vars, not array elements.
407+
let finalleft = left;
408+
let finalmid = mid;
409+
let finalright = right;
410+
if (a[finalleft] > a[finalmid]) {
411+
[finalleft, finalmid] = [finalmid, finalleft];
412+
}
413+
if (a[finalmid] > a[finalright]) {
414+
[finalmid, finalright] = [finalright, finalmid];
415+
if (a[finalleft] > a[finalmid]) {
416+
[finalmid, finalleft] = [finalleft, finalmid];
417+
}
418+
}
419+
420+
390421
// assigning the pivot as the midpoint calculated above
391-
chunker_add_if(QS_BOOKMARKS.MEDIAN3_mid_to_middle_index, (vis, cur_mid, cur_left, cur_right) => {
392-
highlight(vis, cur_mid, false);
393-
// highlight seems to increment counter rather than set flag
394-
if (cur_left !== cur_mid)
395-
highlight(vis, cur_left, false);
396-
highlight(vis, cur_right, false);
422+
chunker_add_if(QS_BOOKMARKS.MEDIAN3_mid_to_middle_index, (vis, fin_mid, fin_left, fin_right) => {
423+
vis.array.selectColor(fin_mid, pivotColor);
424+
vis.array.selectColor(fin_left, partLColor);
425+
vis.array.selectColor(fin_right, partRColor);
426+
// XXX check/fix above for small partitions
397427
},
398-
[mid, left, right]);
428+
[finalmid, finalleft, finalright]);
399429

400430
chunker_add_if(QS_BOOKMARKS.MEDIAN3_first_if_A_idx_left_greater_A_idx_right);
401431
if (a[left] > a[mid]) {
@@ -421,11 +451,11 @@ export function run_QS(is_qs_median_of_3) {
421451
pivot_index = right-1;
422452
chunker_add_if(QS_BOOKMARKS.MEDIAN3_set_pivot_to_value_at_array_indx_right_minus_1,
423453
(vis, cur_right, cur_left, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
424-
unhighlight(vis, cur_right, false);
425-
unhighlight(vis, cur_right -1, false);
454+
// unhighlight(vis, cur_right, false);
455+
// unhighlight(vis, cur_right -1, false);
426456
// unhighlight seems to decrement counter rather than unset flag
427-
if (cur_left !== cur_right -1)
428-
unhighlight(vis, cur_left, false);
457+
// if (cur_left !== cur_right -1)
458+
// unhighlight(vis, cur_left, false);
429459

430460
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) // refresh stack to show pivot_index
431461
},
@@ -439,6 +469,7 @@ export function run_QS(is_qs_median_of_3) {
439469
QS_BOOKMARKS.RIGHT_P_set_pivot_to_value_at_array_indx_right,
440470
(vis, cur_right, cur_left, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
441471
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) // refresh stack to show pivot_index
472+
vis.array.selectColor(cur_pivot_index, pivotColor);
442473
},
443474
[right, left, real_stack, finished_stack_frames, i, j, pivot_index, depth]);
444475
//refresh_stack);
@@ -478,20 +509,37 @@ export function run_QS(is_qs_median_of_3) {
478509
do {
479510
i += 1;
480511

512+
let iColor;
513+
if (a[i] < pivot_value())
514+
iColor = partLColor;
515+
else
516+
iColor = partRColor;
481517
chunker_add_if(
482-
QS_BOOKMARKS.SHARED_incri_i_until_array_index_i_greater_eq_pivot,
483-
refresh_stack);
518+
QS_BOOKMARKS.SHARED_incri_j_until,
519+
(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
520+
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth);
521+
vis.array.selectColor(cur_i, iColor);
522+
});
484523

485524
} while (a[i] < pivot_value());
486525

487526
do {
488527
j -= 1;
489528

529+
let jColor;
530+
if (i <= j && pivot_value() < a[j])
531+
jColor = partRColor;
532+
else
533+
jColor = partLColor;
490534
chunker_add_if(
491535
QS_BOOKMARKS.SHARED_decri_j_until,
492-
refresh_stack);
536+
(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
537+
refresh_stack(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth);
538+
if (cur_j >= left) // XXX pass in left?
539+
vis.array.selectColor(cur_j, jColor);
540+
});
493541

494-
} while (i <= j && pivot_value() < a[j]);
542+
} while (i < j && pivot_value() < a[j]);
495543

496544

497545
chunker_add_if(QS_BOOKMARKS.SHARED_if_j_greater_i);
@@ -507,12 +555,14 @@ export function run_QS(is_qs_median_of_3) {
507555
swapAction(QS_BOOKMARKS.SHARED_swap_pivot_into_position, i,
508556
is_qs_median_of_3 ? right-1 : right
509557
);
510-
558+
// XXX best make pivot sorted above and delete next chunk?
559+
/*
511560
chunker_add_if(
512561
QS_BOOKMARKS.SHARED_swap_pivot_into_position,
513562
(vis, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
514563
vis.array.sorted(cur_pivot_index);
515564
});
565+
*/
516566

517567
return [i, a]; // Return [pivot location, array partition_num_array]
518568
}
@@ -543,15 +593,19 @@ export function run_QS(is_qs_median_of_3) {
543593
// is a chunk at this recursion level as the first chunk in the
544594
// collapsed code for the recursive call
545595
// We no longer want to display 'pivot' or 'j' but want 'i'
596+
// (we use pivot_index but keep pivot for deselect)
546597
let pivot_index = undefined;
547598
let j = undefined;
548599
let i = pivot;
549600
chunker.add(QS_BOOKMARKS.SHARED_pre_left,
550-
(vis, cur_right, cur_left, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) => {
601+
(vis, cur_right, cur_left, cur_real_stack, cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth, old_pivot) => {
551602
refresh_stack(vis, cur_real_stack,
552603
cur_finished_stack_frames, cur_i, cur_j, cur_pivot_index, cur_depth) // refresh shows i
604+
for (let i = cur_left; i <= cur_right; i++)
605+
if (i !== old_pivot)
606+
vis.array.deselect(i);
553607
},
554-
[right, left, real_stack, finished_stack_frames, i, j, pivot_index, depth], depth);
608+
[right, left, real_stack, finished_stack_frames, i, j, pivot_index, depth, pivot], depth);
555609

556610
QuickSort(a, left, pivot - 1, depth + 1);
557611

src/algorithms/controllers/straightRadixSort.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,14 @@ export default {
353353
[nodes, bits]
354354
);
355355

356+
let maxIndex = A.indexOf(savedMax);
356357
chunker.add(SRS_BOOKMARKS.max_number,
357-
(vis, bits, max) => {
358-
// XXX could highlight max in array also?
358+
(vis, bits, max, maxI) => {
359359
vis.mask.setMaxBits(bits);
360360
updateBinary(vis, max);
361+
vis.array.selectColor(maxI, highlightColor);
361362
},
362-
[bits, savedMax]
363+
[bits, savedMax, maxIndex]
363364
);
364365

365366
for (let k = 0; k < bits / RADIX_BITS; k++) {

src/algorithms/pseudocode/MSDRadixSort.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,17 @@ while i < j \\B 303
8282
if we use "break" or similar to exit from this loop.
8383
\\Expl}
8484
\\In{
85-
Repeatedly increment i until i >= j or A[i] has 1 as the mask bit \\B 304
85+
Increment i until the mask bit of A[i] = 1 or i >= j \\B 304
8686
\\Expl{ Scan right looking for a "large" element that is out of
8787
place (mask bit is one). Bitwise "and" between A[i] and mask can be used to
8888
extract the desired bit.
89+
Note we do the tests before incrementing i.
8990
\\Expl}
90-
Repeatedly decrement j until j <= i or A[j] has 0 as the mask bit \\B 305
91+
Decrement j until the mask bit of A[j] = 0 or j <= i \\B 305
9192
\\Expl{ Scan left looking for a "small" element that is out of
9293
place (mask bit is zero). Bitwise "and" between A[i] and mask can be used to
9394
extract the desired bit.
95+
Note we do the tests before decrementing j.
9496
\\Expl}
9597
if i < j \\B 309
9698
\\Expl{ If the indices cross, we exit the loop.

src/algorithms/pseudocode/quickSort.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ Set index i at left the of array segment and j at the right \\Ref init_iAndj
8080
stopping at "small" elements (less than or equal to the pivot).
8181
\\Expl}
8282
while i < j \\B 6
83-
\\Expl{ When the indices cross, all the large elements at the left of
83+
\\Expl{ When the indices meet/cross, all the large elements at the left of
8484
the array segment have been swapped with small elements from the
8585
right of the array segment. The coding here can be simplified
8686
if we use "break" or similar to exit from this loop.
@@ -91,12 +91,14 @@ while i < j \\B 6
9191
performance when there are many equal elements and because
9292
the pivot is in A[right] this also acts as a sentinel, so
9393
we don't increment beyond the right of the array segment.
94+
Note we increment i before the tests.
9495
\\Expl}
95-
Repeatedly decrement j until A[j] <= pivot or j < i \\B 8
96+
Repeatedly decrement j until A[j] <= pivot or j <= i \\B 8
9697
\\Expl{ Stopping at elements equal to the pivot results in better
9798
performance when there are many equal elements. If the
9899
indices cross we exit the outer loop; this also stops us
99100
decrementing beyond the left of the array segment.
101+
Note we decrement j before the tests.
100102
\\Expl}
101103
if j > i \\B 9
102104
\\Expl{ If the indices cross, we exit the loop.

src/components/DataStructures/Array/Array1DRenderer/Array1DRenderer.module.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@
185185

186186
.stackSubElement {
187187
transition-duration: 0.1s;
188-
--j-section: rgb(58, 177, 167);
189-
--i-section: rgb(28, 185, 41);
190-
--p-section: rgb(176, 25, 187); // pink pivot
188+
--j-section: var(--sky);
189+
--p-section: var(--leaf);
190+
--i-section: var(--peach);
191191
}
192192
}
193193

0 commit comments

Comments
 (0)