(* Polyphase sort program. There are n-1 source files for merging and a single output file. The destination of the merged data chabges, when a certain number of runs has been distributed. This number is computed according to a Fibonacci distribution. *) MODULE polysort; FROM InOut IMPORT WriteCard; FROM Terminal IMPORT WriteString, WriteLn, Read; FROM FileSystem IMPORT File, Lookup, Create, Reset, SetPos, GetPos, Response, Close; FROM ByteBlockIO IMPORT ReadByteBlock, WriteByteBlock; CONST n = 6; (* # of files *) numrecs = 10; TYPE item = RECORD key: CARDINAL; END; tapeno = [1..n]; VAR leng,high,low,rand: CARDINAL; eot: BOOLEAN; buf,next: item; f0: File; f: ARRAY [1..n] OF File; ch: CHAR; PROCEDURE list(VAR f: File; n: tapeno); VAR z: CARDINAL; BEGIN z := 0; WriteLn; WriteString(' tape '); WriteCard(n,2); WriteLn; LOOP ReadByteBlock(f,buf); IF f.eof THEN EXIT END; WriteCard(buf.key,5); INC(z); IF z = 15 THEN WriteLn; z := 0 END END; WriteLn; Reset(f) END list; PROCEDURE polyphasesort; VAR i,j,mx,tn,dn,x,min,z: CARDINAL(* tapeno *); k,level:CARDINAL; a,d,last,t,ta: ARRAY tapeno OF CARDINAL; (* a[j] = ideal # of runs on file j *) (* d[j] = # of dummy runs on file *) (* last[j] = key of tail item on tape *) (* t,ta = mappings of tape #'s *) PROCEDURE selectfile; VAR i: tapeno; z: CARDINAL; BEGIN IF d[j] < d[j+1] THEN INC(j) ELSE IF d[j] = 0 THEN INC(level); z := a[1]; FOR i := 1 TO n-1 DO d[i] := z + a[i+1] - a[i]; a[i] := z + a[i+1] END END; j := 1 END; DEC(d[j]); END selectfile; PROCEDURE copyrun; VAR buf,next: item; high,low : CARDINAL; BEGIN (*copy one run from x to y*) ReadByteBlock(f0,next); REPEAT buf := next; IF NOT f0.eof THEN WriteByteBlock(f[j],buf); GetPos(f0,high,low); ReadByteBlock(f0,next); END; UNTIL f0.eof OR (buf.key > next.key); IF NOT f0.eof THEN SetPos(f0,high,low) END; last[j] := buf.key END copyrun; BEGIN (* polyphasesort *) FOR i := 1 TO n(* -1 *) DO a[i] := 1; d[i] := 1; Create(f[i],'DK.') END; level := 1; j := 1; a[n] := 0; d[n] := 0; REPEAT selectfile; copyrun; UNTIL f0.eof OR (j = n-1); LOOP IF f0.eof THEN EXIT END; selectfile; GetPos(f0,high,low); ReadByteBlock(f0,next); SetPos(f0,high,low); IF last[j] <= next.key THEN copyrun; IF f0.eof THEN d[j] := d[j]+1 ELSE copyrun END ELSE copyrun END END; FOR i := 1 TO n-1 DO Reset(f[i]) END; FOR i := 1 TO n DO t[i] := i END; REPEAT z := a[n-1]; d[n] := 0; Close(f[t[n]]); Create(f[t[n]],'DK.'); WriteString(' level'); WriteCard(level,4); WriteLn; WriteString(' tape'); WriteCard(t[n],4); WriteLn; FOR i := 1 TO n DO WriteCard(t[i],6); WriteCard(a[i],6); WriteCard(d[i],6); WriteLn END; REPEAT k := 0; FOR i := 1 TO n-1 DO IF d[i] > 0 THEN DEC(d[i]) ELSE INC(k); ta[k] := t[i] END END; IF k = 0 THEN INC(d[n]) ELSE REPEAT i := 1; mx := 1; GetPos(f[ta[1]],high,low); ReadByteBlock(f[ta[1]],next); SetPos(f[ta[1]],high,low); min := next.key; WHILE i < k DO INC(i); GetPos(f[ta[i]],high,low); ReadByteBlock(f[ta[i]],next); SetPos(f[ta[i]],high,low); x := next.key; IF x < min THEN min := x; mx := i END END; (* ta[mx] has minimal element, move it to t[j] *) ReadByteBlock(f[ta[mx]],buf); WriteByteBlock(f[t[n]],buf); GetPos(f[ta[mx]],high,low); ReadByteBlock(f[ta[mx]],next); eot := f[ta[mx]].eof; SetPos(f[ta[mx]],high,low); IF (buf.key > next.key) OR eot THEN ta[mx] := ta[k]; DEC(k) END UNTIL k = 0; END; DEC(z); UNTIL z = 0; Reset(f[t[n]]); list(f[t[n]],t[n]); tn := t[n]; dn := d[n]; z := a[n-1]; FOR i := n TO 2 BY -1 DO t[i] := t[i-1]; d[i] := d[i-1]; a[i] := a[i-1] - z END; t[1] := tn; d[1] := dn; a[1] := z; DEC(level) UNTIL level = 0; END polyphasesort; BEGIN leng := numrecs; Lookup(f0,'tmp.TEXT',TRUE); IF f0.res # done THEN WriteString(' File not opened. ') END; REPEAT buf.key := leng; WriteCard(buf.key,4); WriteByteBlock(f0,buf); DEC(leng); IF (leng MOD 20) = 0 THEN WriteLn END; UNTIL leng = 0; WriteLn; Reset(f0); list(f0,1); polyphasesort; FOR low := 1 TO n-1 DO Close(f[low]) END; END polysort.