1.
About the code 2.
The Algorithms 2.1.
5.2 Internal Sorting 2.2.
5.2.1 Sorting by Insertion 2.3.
5.2.2 Sorting by Exchanging 2.4.
5.2.3 Sorting by selection 2.5.
5.2.4 Sorting by Merging 2.6.
5.2.5 Sorting by Distribution 3.
Epilog
by Marc Tardif
last updated 2000/01/31
(version 1.1)
also available as XML
This article should be considered an independant re-implementation
of all of Knuth's sorting algorithms from The Art of Programming -
Vol. 3, Sorting and Searching. It provides the C code to every
algorithm discussed at length in section 5.2, Internal Sorting. No explanations
are provided here, the book should provide all the necessary comments. The
following link is a sample implementation to confirm that everything is in
working order: sknuth.c.
| |
In order to remain as true as possible to the book, a few compromises were
taken into consideration. First, the use of goto statements, which are not
recommended as a good programming practice. Nevertheless, as K&R notes: "there
are a few situations where gotos may find a place". Second, Knuth uses arrays
which start at 1 and finish at N inclusively, which is also taken in consi-
deration. Lastly, be warned that there is no error detection in the code,
which is yet another terrible programming practice.
Now that you have been warned, on with the code...
|
| |
| |
Bubble sort
| | | |
B1: BOUND=N;
B2: t=0; for (j=1; j<=BOUND-1; j+=1) {
B3: if (R[j]->K>R[j+1]->K) swap(R[j],R[j+1],Rt); t=j; }
B4: if (t!=0) { BOUND=t; goto B2; }
| | | | |
Merge exchange
| | | |
M1: t=lg(N, HIGH); for (j=1, p=pow(2,t-1); p>=1; p=pow(2,t-(j++))) {
M2: q=pow(2, t-1); r=0; d=p;
M3: for (i=0; i<N-d; i+=1) if ((i&p)==r) {
M4: if (R[i+1]->K>R[i+d+1]->K) swap(R[i+1],R[i+d+1],Rt); }
M5: if (q!=p) { d=q-p; q=q/2; r=p; goto M3; } }
M6: p=p/2; if (p>0) goto M2;
| | | | |
Quicksort
| | | |
Q1: if (N<=M) goto Q9; S=0; l=1; r=N;
Q2: i=l; j=r+1; K=R[l]->K;
Q3: i+=1; if (R[i]->K<K) goto Q3;
Q4: j-=1; if (K<R[j]->K) goto Q4;
Q5: if (j<=i) { swap(R[l],R[j],Rt); goto Q7; }
Q6: swap(R[i],R[j],Rt); goto Q3;
Q7: if (r-j>=j-l>M) { push(j+1,r); S+=1; r=j-1; goto Q2; }
if (j-l>r-j>M) { push(l,j-1); S+=1; l=j+1; goto Q2; }
if (r-j>M>=j-l) { l=j+1; goto Q2; }
if (j-l>M>=r-j) { r=j-1; goto Q2; }
Q8: if (S) { pop(l,r); S-=1; goto Q2; }
Q9: for (j=2; j<=N; j+=1) {
if (R[j-1]->K > R[j]->K) {
K=R[j]->K; Rt=R[j]; i=j-1; R[i+1]=R[i];
while (R[i]->K>K && i>=1) i-=1;
R[i+1]=Rt; } }
| | | | |
Radix exchange sort
| | | |
/* This algorithm, as implemented in the book, seems to have taken a wrong
* turn at Albuquerque. Instead of reading each binary bit of each key from
* left-to-right, they are read from right-to-left. To remedy this problem,
* a few changes have been made to variable 'b' on lines R1 and R8. The code
* seems to work now and Knuth has been advised of this potential problem.
*/
R1: S=0; l=1; r=N; b=N;
R2: if (l==r) goto R10; i=l; j=r;
R3: if (R[i]->K & 1<<(b-1)) goto R6;
R4: i+=1; if (i<=j) goto R3; goto R8;
R5: if (!(R[j+1]->K & 1<<(b-1))) goto R7;
R6: j-=1; if (i<=j) goto R5; goto R8;
R7: swap(R[i],R[j+1],Rt); goto R4;
R8: b-=1; if (b<0) goto R10;
if (j<l || j==r) goto R2;
if (j==l) { l+=1; goto R2; }
R9: push(r,b); r=j; goto R2;
R10: if (S) { l=r+1; pop(r,b); goto R2; }
| | | | |
|
|
| |
It's not because it works that it's necessarily right.
|
This article is Copyright © 1999, 2000 by C-Scene. All Rights Reserved. |