Skip to content

Commit 8ca8f05

Browse files
committed
Merge branch '2024_sem2' into dev
2 parents e89f540 + be3f3c1 commit 8ca8f05

File tree

2 files changed

+273
-10
lines changed

2 files changed

+273
-10
lines changed

src/algorithms/controllers/sorts.c

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
// #define QUICKSORT // some version of quicksort
88
// #define MERGE_TD // top-down merge sort
99
// #define MERGE_BUP // bottom-up merge sort
10+
#define MERGE_NAT // natural merge sort
1011
// #define MSD_RADIX // radix exchange sort
11-
#define MERGE_TD_LA // top-down merge sort for lists imp as arrays
12+
// #define MERGE_TD_LA // top-down merge sort for lists imp as arrays
1213
// XXX should do top-down merge sort for lists imp with pointers - main code
1314
// should be identical - just need to write init code for list and change
1415
// some macro definitions
@@ -59,6 +60,10 @@ List mergesort_td_la(int L, int len);
5960
void mergesort_bup(int A[], int size);
6061
#endif // MERGE_BUP
6162

63+
#ifdef MERGE_NAT
64+
void mergesort_nat(int A[], int size);
65+
#endif // MERGE_NAT
66+
6267
#ifdef MSD_RADIX
6368
int radix_partition(int *A, int left, int right, int mask);
6469
void msd_radix_sort(int A[], int left, int right, int mask);
@@ -102,6 +107,9 @@ main() {
102107
#ifdef MERGE_BUP
103108
mergesort_bup(A, Size-1);
104109
#endif // MERGE_BUP
110+
#ifdef MERGE_NAT
111+
mergesort_nat(A, Size-1);
112+
#endif // MERGE_NAT
105113
for (i=1; i < Size; i++) printf("%d ", A[i]); printf("\n");
106114
}
107115

@@ -323,7 +331,7 @@ mergesort_td(int A[], int left, int right) {
323331
List
324332
mergesort_td_la(int L, int len) {
325333
int i, mid;
326-
List Lmid, R, M, E;
334+
List Lmid, R, M, Mlast;
327335

328336
if (len > 1) {
329337
// determine Lmid, the mid point of L
@@ -362,23 +370,23 @@ mergesort_td_la(int L, int len) {
362370
R = tail(R);
363371
}
364372
// scan through adding elements to the end of M
365-
E = M;
373+
Mlast = M;
366374
while (L != Null && R != Null) {
367375
if (head(L) <= head(R)) {
368-
tail(E) = L;
369-
E = L;
376+
tail(Mlast) = L;
377+
Mlast = L;
370378
L = tail(L);
371379
} else {
372-
tail(E) = R;
373-
E = R;
380+
tail(Mlast) = R;
381+
Mlast = R;
374382
R = tail(R);
375383
}
376384
}
377385
// add any elements not scanned to the end of M
378386
if (L == Null)
379-
tail(E) = R;
387+
tail(Mlast) = R;
380388
else
381-
tail(E) = L;
389+
tail(Mlast) = L;
382390
printf("Merged: ");
383391
for (Lmid = M; Lmid != Null; Lmid = tail(Lmid))
384392
printf(" %d", head(Lmid));
@@ -397,7 +405,7 @@ mergesort_td_la(int L, int len) {
397405
#endif // MERGE_TD_LA
398406

399407
#ifdef MERGE_BUP
400-
// XXX could reduce duplication with MERGE_TD
408+
// XXX could reduce duplication with MERGE_TD and MERGE_NAT
401409
int B[Size];
402410

403411
int
@@ -460,3 +468,77 @@ printf("Merging %d %d %d - %d\n", left, mid, right, runlength);
460468
}
461469

462470
#endif // MERGE_BUP
471+
472+
#ifdef MERGE_NAT
473+
// XXX could reduce duplication with MERGE_TD and MERGE_BUP
474+
int B[Size];
475+
476+
int
477+
minimum(int i, int j) {
478+
if (i <= j)
479+
return i;
480+
else
481+
return j;
482+
}
483+
484+
// Sort array A[1]..A[size] in ascending order
485+
void
486+
mergesort_nat(int A[], int size) {
487+
int runcount, left, mid, right;
488+
int ap1, ap1max, ap2, ap2max, bp;
489+
490+
do {
491+
runcount = 0;
492+
left = 1;
493+
do {
494+
// find the first run, A[left..mid]
495+
mid = left;
496+
while (mid < size && A[mid] <= A[mid+1])
497+
mid++;
498+
// find the second run, A[mid+1..right]
499+
right = mid+1;
500+
while (right < size && A[right] <= A[right+1])
501+
right++;
502+
if (mid < size) {
503+
// merge A[left..mid] and A[mid+1..right], with the result in A
504+
printf("Merging %d %d %d \n", left, mid, right);
505+
ap1 = left;
506+
ap1max = mid;
507+
ap2 = mid+1;
508+
ap2max = right;
509+
bp = left;
510+
while (ap1 <= ap1max && ap2 <= ap2max)
511+
if (A[ap1] < A[ap2]) {
512+
B[bp] = A[ap1];
513+
ap1 = ap1+1;
514+
bp = bp+1;
515+
} else {
516+
B[bp] = A[ap2];
517+
ap2 = ap2+1;
518+
bp = bp+1;
519+
}
520+
while (ap1 <= ap1max) {
521+
B[bp] = A[ap1];
522+
ap1 = ap1+1;
523+
bp = bp+1;
524+
}
525+
while (ap2 <= ap2max) {
526+
B[bp] = A[ap2];
527+
ap2 = ap2+1;
528+
bp = bp+1;
529+
}
530+
for (bp = left; bp <= right; bp++)
531+
A[bp] = B[bp];
532+
}
533+
runcount++;
534+
left = right + 1;
535+
} while (left < size);
536+
} while (runcount > 1);
537+
// if (left < right-1) { // for testing/debugging
538+
// int i1;
539+
// printf("Ret from ms(%d, %d): ", left, right);
540+
// for (i1=1; i1 < Size; i1++) printf("%d ", A[i1]); printf("\n");
541+
// }
542+
}
543+
544+
#endif // MERGE_NAT
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import parse from '../../pseudocode/parse';
2+
3+
export default parse(`
4+
\\Note{ Natural merge sort. This is a copied+modified version of the
5+
bottom up mergesort pseudocode (possibly not the final version) which
6+
was a copied+modified version of the top down mergesort pseudocode.
7+
There is a fair bit of commonality (including the merge code).
8+
\\Note}
9+
10+
\\Code{
11+
Main
12+
// Sort array A[1]..A[size] in ascending order
13+
NaturalMergesort(A, size) \\B Main
14+
do \\B MainWhile
15+
\\In{
16+
merge all consecutive pairs of runs \\Ref MergeAll
17+
\\In}
18+
until there is only one run
19+
\\Expl{ Each iteration typically halves the number of runs and when
20+
there is only one left the array is sorted. During the merging
21+
of consecutive runs we count the number of runs.
22+
\\Expl}
23+
\\Code}
24+
25+
\\Code{
26+
MergeAll
27+
runcount <- 0 // we count the runs (for the outer loop condition)
28+
left <- 1 \\B left
29+
do \\B MergeAllWhile
30+
find the first run, A[left..mid] \\Ref FirstRun
31+
\\Expl{ We compute mid to get the longest sequence where A[left] <=
32+
A[left+1] <= ... <= A[mid].
33+
\\Expl}
34+
find the second run, A[mid+1..right] // could be empty \\Ref SecondRun
35+
\\Expl{ We compute right to get the longest sequence where A[mid+1] <=
36+
A[mid+2] <= ... <= A[right]. If mid = size this will be empty.
37+
\\Expl}
38+
if mid < size // if the second run isn't empty
39+
\\Expl{ If the number of runs is odd, the last one
40+
found doesn't need to be merged. This test could be
41+
moved before the code to find the second run and/or used to
42+
break out of the loop.
43+
\\Expl}
44+
\\In{
45+
merge A[left..mid] and A[mid+1..right], with the result in A \\Ref MergeCopy
46+
\\In}
47+
runcount <- runcount + 1
48+
left <- right + 1 // skip to the next pair of runs (if any) \\B left2
49+
until left >= size
50+
\\In}
51+
\\Code}
52+
53+
\\Code{
54+
FirstRun
55+
mid <- left
56+
while mid < size and A[mid] <= A[mid+1]
57+
\\Expl{ Scan until we find an element that is less than the previous
58+
element (or we reach the end).
59+
\\Expl}
60+
\\In{
61+
mid <- mid + 1
62+
\\In}
63+
\\Code}
64+
65+
\\Code{
66+
SecondRun
67+
right <- mid + 1
68+
while right < size and A[right] <= A[right+1]
69+
\\Expl{ Scan until we find an element that is less than the previous
70+
element (or we reach the end).
71+
\\Expl}
72+
\\In{
73+
right <- right + 1
74+
\\In}
75+
\\Code}
76+
77+
\\Note{
78+
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX following verbatim from top-down mergesort
79+
\\Note}
80+
81+
\\Code{
82+
MergeCopy
83+
Merge(A, left, mid, right, B) \\Ref Merge
84+
\\Expl{ Takes two sorted array segments, A[left..mid] and A[mid+1..right],
85+
and merges them together to form a single sorted array segment
86+
in temporary array B[left..right].
87+
The animation shows values being deleted from A since they
88+
are no longer needed (they are actually still there).
89+
\\Expl}
90+
Copy merged elements back to A \\B copyBA
91+
\\Expl{ Copy elements from B[left..right] back to A[left..right].
92+
Copying can be reduced by merging
93+
from A to B and from B to A in alternate levels of recursion -
94+
a slightly more tricky coding.
95+
The animation shows values being deleted from B since they
96+
are no longer needed (they are actually still there).
97+
\\Expl}
98+
\\Note{ Might be better to move above to overview.
99+
\\Note}
100+
\\Code}
101+
102+
\\Code{
103+
Merge
104+
ap1 <- left \\B ap1
105+
max1 <- mid \\B max1
106+
\\Expl{ ap1 scans through the segment A[left..mid], "pointing at" or
107+
indexing elements of this array segment we copy from.
108+
\\Expl}
109+
ap2 <- max1+1 \\B ap2
110+
max2 <- right \\B max2
111+
\\Expl{ ap2 scans through the segment A[mid+1..right], "pointing at" or
112+
indexing elements of this array segment we copy from.
113+
\\Expl}
114+
bp <- ap1 \\B bp
115+
\\Expl{ bp scans through the segment B[left..right], "pointing at" or
116+
indexing elements of this array segment we copy to.
117+
\\Expl}
118+
while both A segments still have elements to copy \\Ref MergeWhile
119+
\\Expl{ we scan through both A segments from left to right by
120+
incrementing ap1 and ap2, copying to B as we go.
121+
The animation shows values being deleted from A since they
122+
are no longer needed (they are actually still there).
123+
\\Expl}
124+
\\In{
125+
copy the smaller A element, increment its pointer and bp \\Ref CopySmaller
126+
\\Expl{ The smaller of A[ap1] and A[ap2] is copied to B[bp].
127+
\\Expl}
128+
\\In}
129+
copy any remaining elements from A to B \\Ref CopyRest
130+
\\Expl{ One of the A segments will have been completely copied;
131+
the other has uncopied elements.
132+
\\Expl}
133+
\\Code}
134+
135+
\\Code{
136+
MergeWhile
137+
while ap1 <= max1 and ap2 <= max2 \\B MergeWhile
138+
\\Expl{ Elements up to max1/max2 must be copied; those before
139+
ap1/ap2 have been copied already.
140+
\\Expl}
141+
\\Code}
142+
143+
\\Code{
144+
CopySmaller
145+
if A[ap1] < A[ap2] \\B findSmaller
146+
\\In{
147+
B[bp] <- A[ap1] \\B copyap1
148+
\\Expl{ The animation shows the value being deleted from A[ap1] since it
149+
is no longer needed (it is actually still there).
150+
\\Expl}
151+
ap1 <- ap1+1 \\B ap1++
152+
bp <- bp+1 \\B bp++
153+
\\Note{ Clearer to duplicate this in then and else branches(?)
154+
\\Note}
155+
\\In}
156+
else
157+
\\In{
158+
B[bp] <- A[ap2] \\B copyap2
159+
\\Expl{ The animation shows the value being deleted from A[ap2] since it
160+
is no longer needed (it is actually still there).
161+
\\Expl}
162+
ap2 <- ap2+1 \\B ap2++
163+
bp <- bp+1 \\B bp++_2
164+
\\In}
165+
\\Code}
166+
167+
\\Code{
168+
CopyRest
169+
copy A[ap1..max1] to B[bp..] \\B CopyRest1
170+
\\Note{ Need to expand this? I dont think so.
171+
\\Note}
172+
copy A[ap2..max2] to B[bp..] \\B CopyRest2
173+
\\Expl{ One of these copy steps will do nothing because one of the
174+
A segments will be empty. If ap2 is not shown in the animation
175+
it is max2+1, off the end of the array.
176+
The animation shows values being deleted from A since they
177+
are no longer needed (they are actually still there).
178+
\\Expl}
179+
\\Code}
180+
181+
`);

0 commit comments

Comments
 (0)