Initial data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 72d218235f
commit f23f22d71c
199087 changed files with 3378941 additions and 0 deletions

View file

@ -0,0 +1,5 @@
DEFINITION MODULE MSIterat;
PROCEDURE IterativeMergeSort( VAR a : ARRAY OF INTEGER);
END MSIterat.

View file

@ -0,0 +1,82 @@
IMPLEMENTATION MODULE MSIterat;
IMPORT Storage;
PROCEDURE IterativeMergeSort( VAR a : ARRAY OF INTEGER);
VAR
n, bufLen, len, endBuf : CARDINAL;
k, nL, nR, b, h, i, j, startR, endR: CARDINAL;
temp : INTEGER; (* array element *)
pbuf : POINTER TO ARRAY CARDINAL OF INTEGER;
BEGIN
n := HIGH(a) + 1; (* length of array *)
IF (n < 2) THEN RETURN; END;
(* Sort blocks of length 2 by swapping elements if necessary.
Start at high end of array; ignore a[0] if n is odd.*)
k := n;
REPEAT
DEC(k, 2);
IF (a[k] > a[k + 1]) THEN
temp := a[k]; a[k] := a[k + 1]; a[k + 1] := temp;
END;
UNTIL (k < 2);
IF (n = 2) THEN RETURN; END;
(* Set up a buffer for temporary storage when merging. *)
(* TopSpeed Modula-2 doesn't seem to have dynamic arrays,
so we use a workaround *)
bufLen := n DIV 2;
Storage.ALLOCATE( pbuf, bufLen*SIZE(INTEGER));
nR := 2; (* length of right-hand block when merging *)
REPEAT
len := 2*nR; (* maximum length of a merged block in this iteration *)
k := n; (* start at the high end of the array *)
WHILE (k > nR) DO
IF (k >= len) THEN
nL := nR; DEC(k, len);
ELSE
nL := k - nR; k := 0; END;
(* Merging 2 adjacent blocks, already sorted.
k = start index of left block;
nL, nR = lengths of left and right blocks *)
startR := k + nL; endR := startR + nR;
(* Skip elements in left block that are already in correct place *)
temp := a[startR]; (* first (smallest) element in right block *)
j := k;
WHILE (j < startR) AND (a[j] <= temp) DO INC(j); END;
endBuf := startR - j; (* length of buffer actually used *)
IF (endBuf > 0) THEN (* if endBuf = 0 then already sorted *)
(* Copy from left block to buffer, omitting elements
that are already in correct place *)
h := j;
FOR b := 0 TO endBuf - 1 DO
pbuf^[b] := a[h]; INC(h);
END;
(* Fill in values from right block or buffer *)
b := 0;
i := startR;
(* j = startR - endBuf from above *)
WHILE (b < endBuf) AND (i < endR) DO
IF (pbuf^[b] <= a[i]) THEN
a[j] := pbuf^[b]; INC(b)
ELSE
a[j] := a[i]; INC(i); END;
INC(j);
END;
(* If now b = endBuf then the merge is complete.
Else just copy the remaining elements in the buffer. *)
WHILE (b < endBuf) DO
a[j] := pbuf^[b]; INC(j); INC(b);
END;
END;
END;
nR := len;
UNTIL (nR >= n);
Storage.DEALLOCATE( pbuf, bufLen*SIZE(INTEGER));
END IterativeMergeSort;
END MSIterat.

View file

@ -0,0 +1,32 @@
MODULE MSItDemo;
(* Demo of iterative merge sort *)
IMPORT IO, Lib;
FROM MSIterat IMPORT IterativeMergeSort;
(* Procedure to display the values in the demo array *)
PROCEDURE Display( VAR a : ARRAY OF INTEGER);
VAR
j, nrInLine : CARDINAL;
BEGIN
nrInLine := 0;
FOR j := 0 TO HIGH(a) DO
IO.WrCard( a[j], 5); INC( nrInLine);
IF (nrInLine = 10) THEN IO.WrLn; nrInLine := 0; END;
END;
IF (nrInLine > 0) THEN IO.WrLn; END;
END Display;
(* Main routine *)
CONST
ArrayLength = 50;
VAR
arr : ARRAY [0..ArrayLength - 1] OF INTEGER;
m : CARDINAL;
BEGIN
Lib.RANDOMIZE;
FOR m := 0 TO ArrayLength - 1 DO arr[m] := Lib.RANDOM( 1000); END;
IO.WrStr( 'Before:'); IO.WrLn; Display( arr);
IterativeMergeSort( arr);
IO.WrStr( 'After:'); IO.WrLn; Display( arr);
END MSItDemo.

View file

@ -0,0 +1,20 @@
DEFINITION MODULE MergSort;
TYPE MSCompare = PROCEDURE( ADDRESS, ADDRESS) : INTEGER;
TYPE MSGetNext = PROCEDURE( ADDRESS) : ADDRESS;
TYPE MSSetNext = PROCEDURE( ADDRESS, ADDRESS);
PROCEDURE DoMergeSort( VAR start : ADDRESS;
Compare : MSCompare;
GetNext : MSGetNext;
SetNext : MSSetNext);
(*
Procedures to be supplied by the caller:
Compare(a1, a2) returns -1 if a1^ is to be placed before a2^;
+1 if after; 0 if no priority.
GetNext(a) returns address of next item after a^.
SetNext(a, n) sets address of next item after a^ to n.
If a^ is last item, then address of next item is NIL.
It can be assumed that a, a1, a2 are not NIL.
*)
END MergSort.

View file

@ -0,0 +1,55 @@
IMPLEMENTATION MODULE MergSort;
PROCEDURE DoMergeSort( VAR start : ADDRESS;
Compare : MSCompare;
GetNext : MSGetNext;
SetNext : MSSetNext);
VAR
p1, p2, q : ADDRESS;
BEGIN
(* If list has < 2 items, do nothing *)
IF (start = NIL) THEN RETURN; END;
p1 := GetNext( start); IF (p1 = NIL) THEN RETURN; END;
(* If list has only 2 items, we'll not use recursion *)
p2 := GetNext( p1);
IF (p2 = NIL) THEN
IF (Compare( start, p1) > 0) THEN
q := start; SetNext( p1, q); SetNext( q, NIL);
start := p1;
END;
RETURN;
END;
(* List has > 2 items: split list in half *)
p1 := start;
REPEAT
p1 := GetNext( p1);
p2 := GetNext( p2);
IF (p2 <> NIL) THEN p2 := GetNext( p2); END;
UNTIL (p2 = NIL);
(* Now p1 points to last item in first half of list *)
p2 := GetNext( p1); SetNext( p1, NIL);
p1 := start;
(* Recursive calls to sort each half; p1 and p2 will be updated *)
DoMergeSort( p1, Compare, GetNext, SetNext);
DoMergeSort( p2, Compare, GetNext, SetNext);
(* Merge the sorted halves *)
IF Compare( p1, p2) < 0 THEN
start := p1; p1 := GetNext( p1);
ELSE
start := p2; p2 := GetNext( p2);
END;
q := start;
WHILE (p1 <> NIL) AND (p2 <> NIL) DO
IF Compare( p1, p2) < 0 THEN
SetNext( q, p1); q := p1; p1 := GetNext( p1);
ELSE
SetNext( q, p2); q := p2; p2 := GetNext( p2);
END;
END;
IF (p1 = NIL) THEN SetNext( q, p2) ELSE SetNext( q, p1) END;
END DoMergeSort;
END MergSort.

View file

@ -0,0 +1,75 @@
MODULE MergDemo;
IMPORT IO, Lib, MergSort;
TYPE PTestRec = POINTER TO TestRec;
TYPE TestRec = RECORD
Value : INTEGER;
Next : PTestRec;
END;
PROCEDURE Compare( a1, a2 : ADDRESS) : INTEGER;
VAR
p1, p2 : PTestRec;
BEGIN
p1 := a1; p2 := a2;
IF (p1^.Value < p2^.Value) THEN RETURN -1
ELSIF (p1^.Value > p2^.Value) THEN RETURN 1
ELSE RETURN 0; END;
END Compare;
PROCEDURE GetNext( a : ADDRESS) : ADDRESS;
VAR
p : PTestRec;
BEGIN
p := a; RETURN p^.Next;
END GetNext;
PROCEDURE SetNext( a, n : ADDRESS);
VAR
p : PTestRec;
BEGIN
p := a; p^.Next := n;
END SetNext;
(* Display the values in the linked list *)
PROCEDURE Display( p : PTestRec);
VAR
nrInLine : CARDINAL;
BEGIN
nrInLine := 0;
WHILE (p <> NIL) DO
IO.WrCard( p^.Value, 5);
p := p^.Next;
INC( nrInLine);
IF (nrInLine = 10) THEN IO.WrLn; nrInLine := 0; END;
END;
IF (nrInLine > 0) THEN IO.WrLn; END;
END Display;
(* Main routine *)
CONST ArraySize = 50;
VAR
arr : ARRAY [0..ArraySize - 1] OF TestRec;
j : CARDINAL;
start, p : PTestRec;
BEGIN
(* Fill values with random integers *)
FOR j := 0 TO ArraySize - 1 DO
arr[j].Value := Lib.RANDOM( 1000);
END;
(* Set up the links *)
IF (ArraySize > 1) THEN (* FOR loop 0 TO -1 crashes program *)
FOR j := 0 TO ArraySize - 2 DO
arr[j].Next := ADR( arr[j + 1]);
END;
END;
arr[ArraySize - 1].Next := NIL;
(* Demonstrate merge sort on the linked list *)
start := ADR( arr[0]);
IO.WrStr( 'Before:'); IO.WrLn;
Display( start);
MergSort.DoMergeSort( start, Compare, GetNext, SetNext);
IO.WrStr( 'After:'); IO.WrLn;
Display( start);
END MergDemo.