``````{I wrote a small Program to bench both sort routines we posted. It was an
interesting test, however it did raise a couple questions For me, which I'll
get to in a moment. (The following Program can be used as a skeleton For trying
other sort routines too.)

Needless to say, the routine you posted was dramatically faster than the one I
posted, even though both routines are non-recursive simple sorts.

The maximum efficient load of the routine you posted appears to be about 3000
elements. After that, additonal elements add time exponentially. For example,
it will sort 3000 elements in 5.1 seconds, but 5000 elements takes almost 16
seconds. The sort I posted became un-benchable [bearable] at about 3000
elements when it took over a minute to Complete. I didn't test it beyond this
point.

Here are the results from my 386 33Mhz machine-- your algorithm.

500 Elements - 0.1   Seconds
1000 Elements - 0.8   Seconds
1500 Elements - 1.4   Seconds
2000 Elements - 2.6   Seconds
3000 Elements - 5.1   Seconds  <- Peak efficiency reached
5000 Elements - 15.8  Seconds

Here is the Program I used to benchmark with. I made it so that you could
"tweak" portions of the sort and re-run the Program.

Incidentally, I also Compiled this Program under Stony Brook's Pascal Plus and
was suprised to find that it ran substantially slower. All optimizations on.

Range Checking (\$R+) exactly Doubled the time it took to sort.

Changing "Span+1" to Succ(Span) and "total-1" to Pred(total) made the routine
about 3% faster. However the routine then neglected to sort that last two
elements. Adding "Inc(total,2)" solved the problem but I'm not sure why. I did
not expect this behavior. Perhaps someone could explain why?

I added a temporary Pointer Variable to your routine in place of the "NewStr('
...  ')" code you used to simplify it.

and one last thing... Using OPRO's OpInline Function called
"ExchangeLongInts()" to do the swapping instead of using a temporary Var
increased speed another 2% (Evident at > 2000 elements.) However I did not
include this so that anyone interested could Compile and run this without extra
Units.
}

{\$A+,B-,D-,E-,F-,G-,I+,L+,N-,O-,P-,Q+,R-,S+,T-,V-,X-,Y+}
{\$M 32768,0,655360}

Program Sort_Test;  { Sorting Benchmark Using P. Beeftink's Algorithm }

Type
SmallArrPtr = ^SmallArr;
SmallArr    = Array[1..10] of Char;   { Skip String & Length Byte }

TTimeString = String[20];

Var
SortArray : Array[1..5000] of SmallArrPtr; { A LARGE Array }

TickCount : LongInt Absolute \$0040:\$006C;
{ TickCount : LongInt VOLATILE Absolute \$0040:\$006C; } { For Pascal+ }
Tstart,
Ttime     : LongInt;

{------------------------------------------------------------------------}
Procedure StartTiming;
begin
TStart := TickCount;

{start at the beginning of a tick!}
Repeat Until TStart <> TickCount;

TStart := TickCount;

end;
{------------------------------------------------------------------------}
Procedure StopTiming;
begin
TTime := TickCount - TStart;
end;
{------------------------------------------------------------------------}
Function Elapsed : TTimeString;
Var Temp : TTimeString;
Sec10 : LongInt;
begin

Sec10 := TTime * 2470 div 4497;
Str( Sec10 : 4, Temp );

if Temp[1] = ' ' then Temp[1] := '0';

Inc( Temp[0] );
Temp[ Length(Temp) ] := Temp[ Pred( Length( Temp ) ) ];
Temp[ Pred( length( Temp ) ) ] := '.';

Elapsed := Temp;
end;
{------------------------------------------------------------------------}
Procedure MakeRandomStrings( NumtoMake : Word );
Var RNum,
I,S  : Word;
Temp : String;
begin

Temp := '';
Temp[0] := Chr( 10 );
Randomize;

For I := 1 to NumtoMake do
begin

For S := 1 to 10 do     { Create Random Strings 10 Chars in length }
begin
RNum := Random(26);
Temp[S] := Chr( RNum + 65 );
end;

Move( Temp[1], SortArray[I]^, 10 );

end;

end; { Proc }
{------------------------------------------------------------------------}
Procedure KDSort( total : Word );
{-My simple sort routine as posted in Pascal Echo }
{ With 2 slight modifications                     }
Var
i,j,
Current : Word;
TempPtr : Pointer;
begin

For I := 1 to total do
begin

Current := I;

For J := Succ(I) to total do
begin
if SortArray[J]^ < SortArray[Current]^ then
begin
TempPtr            := SortArray[j];
SortArray[j]       := SortArray[Current];
SortArray[Current] := TempPtr;
end; {if}
end; {For}

end; {For}

end;
{------------------------------------------------------------------------}
Procedure PBSort(total : Integer);
{-Peter Beeftink's Sort as Posted in Pascal Echo }
{ Also With slight modifications                 }
Var
I,j     : Integer;
Span    : Integer;
TempPtr : Pointer;
begin

Inc(total,2);   { Required to Compensate For PRED and SUCC ? }

Span := total SHR \$01;

While Span > 0 do
begin

For I := Span to Pred(total) {total-1} do
begin

For j := (I - Succ(Span) {Span+1} ) Downto 1 do
if (SortArray[j]^ <= SortArray[j+Span]^) then j := 1 else
begin
TempPtr           := SortArray[j];
SortArray[j]      := SortArray[j+Span];
SortArray[j+Span] := TempPtr;
end;

end; {For}

Span := Span SHR \$01; { This does help speed over Span div 2! }

end; {WhIle}

end;
{------------------------------------------------------------------------}
Procedure Do_Sorting( SortAmount : Word );
begin

MakeRandomStrings(SortAmount);

Write('Sorting... ');

StartTiming;

PBSort(SortAmount); { Change to KDSort() to bench second sort routine }

StopTiming;

WriteLn(SortAmount:5,' Elements - ',Elapsed,' Seconds');

end;
{------------------------------------------------------------------------}
Var C : Word;

begin

if MaxAvail < 5000 * Sizeof(SmallArr) then Halt; { not enough memory! }

For C := 1 to 5000 do   { pre-allocate up front }
GetMem(SortArray[C],Sizeof(SmallArr));

Do_Sorting( 500   );   { Add more Do_Sorting()'s For whatever count }
Do_Sorting( 1000  );   { you wish to test with.                     }
Do_Sorting( 1500  );
Do_Sorting( 2000  );
Do_Sorting( 3000  );
Do_Sorting( 5000  );

{ Un-comment the following if you wish to see the sorted output }

{
For C := 1 to 5000 do   { Change 5000 to the amount you sorted }
WriteLn( SortArray[C]^ );

For C := 1 to 5000 do
FreeMem(SortArray[C],Sizeof(SmallArr));

end.
{
I plugged in a QuickSort algorithm in the "skeleton" Program in my previous
message to test perFormance. Here are the results:

500 Elements - 0.1 Seconds
1000 Elements - 0.2 Seconds
1500 Elements - 0.4 Seconds
2000 Elements - 0.6 Seconds
3000 Elements - 0.9 Seconds
5000 Elements - 1.8 Seconds

Very fast indeed. I modified the algorithm to sort only by Pointers, and
optimized a couple spots. Again, a slight speed increase is noted using OPRO's
ExchangeLongInts() in leu of using temporary Variables in 1 spot. if you have
OPRO, replace them and you reduce the number of instructions by 2 per
iteration.

This is a split-list recursive sort. Works by making a pass through the entire
Array first and moves all "small" data to the left, and all "Large" data to the
right. then it sorts each half seperately.

Take the following code segment and "plug" it into the skeleton in my previous
message. then change the "PBSort(SortAmount)" to "QuickSort(SortAmount)" to run
the tests.

Here is the code segment:

{------------------------------------------------------------------------}
Procedure QuickSort( total : Integer );
{------------------------------------------}
Procedure recQuickSort( L, R : Integer );
Var K,I,J   : Integer;
T,
Temp    : Pointer;

begin

if L < R then
begin
T := SortArray[L];
I := Pred(L);
J := L;
K := Succ(R);

While Succ(J) < K do
if SortArray[Succ(J)]^ < SmallArrPtr(T)^ then
begin
Inc(I,1);
Inc(J,1);
SortArray[I] := SortArray[J];
SortArray[j] := T;
end {if}
else
if SortArray[Succ(J)]^ > SmallArrPtr(T)^ then
begin
Dec(K,1);
Temp := SortArray[K];
SortArray[K] := SortArray[Succ(J)];
SortArray[Succ(J)] := Temp;
end {if}
else
Inc(J,1);

recQuickSort(L,I);
recQuickSort(K,R);

end; { if L < R }

end; { Proc recQuickSort }
{------------------------------------------}

begin

recQuickSort(1,total);

end;{QuickSort}
{------------------------------------------------------------------------}

``````