[Back to SORTING SWAG index]  [Back to Main SWAG index]  [Original]


{ I've been working on a project for most of this year found the SWAG
group a valuable resource for ideas. I've written a mergesort that I
thought others may find of interest. It is written for a doubly
linked list because that is what I needed, but I'm sure it can be
adapted for a single linked list and with a bit more work probably 
arrays.

On a 486DX-50 it repeatly sorted a list of 20000 elements in less
than 0.9 of a second (unless I've done something wrong with the 
timing).

It is wrapped up in a test program and generates an output file
called 'SORTTEXT.TXT' which includes the initial unsorted list, the
sorted list and the approximate time taken to sort the list. It
should compile straight away.
}

program MergeTest;

uses Dos;{for GetTime}

type
   PNodeType = ^NodeType;

   NodeType = record Val  : integer;   {The Value of the node} 
      Prev : PNodeType; {The Previous Node in the List. This equals nil when first in list} 
      Next : PNodeType; {The Next Node in the List. This equals nil when last in list} 
   end;

var
   TheList      : PNodeType;
   TempList     : PNodeType;

   N            : integer;
   Count        : integer;

   OutFile      : text;

   Hundredths   : word;    {                               }
   Hundredths2  : word;    {                               }
   Seconds      : word;    {                               }
   Seconds2     : word;    {                               }
   Minutes      : word;    {       Used for timing         }
   Minutes2     : word;    {                               }
   Hours        : word;    {                               }
   Hours2       : word;    {                               }
   Total        : longint; {                               }
   Total2       : longint; {                               }

   procedure ShowList(TheList : PNodeType);
   {This procedure will take a List of PNodeType and write it to a file}

   var
      Count    : integer;
      TempList : PNodeType;

   begin
      TempList := TheList;
      Count := 1;
      while TempList <> nil do
      begin
         if TempList^.Prev <> nil then
            writeln(OutFile,'  Prev : ',TempList^.Prev^.Val)
         else
            writeln(OutFile,'  Prev = nil');

         writeln(OutFile,'Val No : ',Count,' is ',TempList^.Val);

         if TempList^.Next <> nil then
            writeln(OutFile,'  Next : ',TempList^.Next^.Val)
         else
            writeln(OutFile,'  Next = nil');

         writeln(OutFile);
         TempList := TempList^.Next;
         inc(Count);
      end;
      writeln(OutFile,'The Node = nil');
      writeln(OutFile);
   end;



   function MergeSort(TheList : PNodeType; N : integer) : PNodeType;
   {This procedure is the MergeSort. It recursively calls itself to sort the
    list}

   var
      TempNode1  : PNodeType;
      TempNode2  : PNodeType;
      Count      : integer;
      Size1      : integer;
      Size2      : integer;
      UsingList1 : boolean;

   begin
      {check for two or less elements}

      if N <= 2 then
      begin
         if N = 1 then               {one element in the list}
            MergeSort := TheList     {a one element list is already sorted}
         else
         begin                       {two elements in the list}

            {if the two elements are already sorted, return the list else
             swap them and return the list}

            if TheList^.Val < TheList^.Next^.Val then
               MergeSort := TheList
            else
            begin
               TempNode1 := TheList;
               TempNode2 := TheList^.Next;
               TempNode1^.Prev := TempNode2;
               TempNode2^.Next := TempNode1;
               TempNode1^.Next := nil;
               TempNode2^.Prev := nil;
               MergeSort := TempNode2;
            end;
         end;
      end
      else
      begin
         {more than two element in the list}

         {split the list in to two half lists}
            {TempNode1 holds the first list}
            {TempNode2 holds the second list}

         TempNode2 := TheList;
         Size1 := N div 2;
         Size2 := n - Size1;
         for Count := 1 to Size1 - 1 do
            TempNode2 := TempNode2^.Next;
         TempNode1 := TempNode2;
         TempNode2 := TempNode2^.Next;
         TempNode1^.Next := nil;
         TempNode2^.Prev := nil;
         TempNode1 := TheList;

         {sort the two half lists}

         TempNode1 := MergeSort(TempNode1,Size1);
         TempNode2 := MergeSort(TempNode2,Size2);


         {Merge the two sorted lists}
            {Select which list to start with}
            {When UsingList1 is true then the list being moved through is
             the first list (TempNode1) else it is the second list
             (TempNode2)}

         if TempNode1^.Val < TempNode2^.Val then
         begin
            MergeSort := TempNode1;
            UsingList1 := true;
         end
         else
         begin
            MergeSort := TempNode2;
            UsingList1 := false;
         end;

         while (TempNode1 <> nil) and (TempNode2 <> nil) do
         begin
            {A procedure could be used to replace the two branches of this
             if statement}

            {This is where the merge takes place}

            if UsingList1 then
            begin
               while (TempNode1^.next <> nil) and
                     (TempNode1^.Next^.Val < TempNode2^.Val) do
                                {^ Sort criteria ^}
                  TempNode1 := TempNode1^.Next;
               TempNode2^.Prev := TempNode1;
               TempNode1 := TempNode1^.Next;
               TempNode2^.Prev^.Next := TempNode2;
               if TempNode1 = nil then
                  exit;
            end
            else
            begin
               while (TempNode2^.next <> nil) and
                     (TempNode2^.Next^.Val < TempNode1^.Val) do
                                {^ Sort criteria ^}
                  TempNode2 := TempNode2^.Next;
               TempNode1^.Prev := TempNode2;
               TempNode2 := TempNode2^.Next;
               TempNode1^.Prev^.Next := TempNode1;
               if TempNode2 = nil then
                  exit;
            end;
            UsingList1 := not UsingList1;
         end;

      end;
   end;


begin
   {Small piece of code to test the sort}
   N := 20000;                        {Change this to vary the number of
                                       elements in the linked list}
   randomize;

   {Create the list}

   writeln('Initialising List');
   new(TheList);
   TheList^.Val := random(500);
   TheList^.Prev := nil;
   TempList := TheList;
   for Count := 2 to N do
   begin
      new(TempList^.Next);
      TempList^.Next^.Prev := TempList;
      TempList := TempList^.Next;
      TempList^.Val := random(500);
   end;
   TempList^.next := nil;

   {Write the list to file}
   writeln('Writing Initial list to file');
   assign(OutFile,'SortText.Txt');              {The name of the output file}
   rewrite(OutFile);
   writeln(OutFile,'----- Initial List -----');
   writeln(OutFile);
   ShowList(TheList);
   close(OutFile);

   writeln('Sorting List of ', N ,' elements');
   {Get the start time}
   GetTime(Hours,Minutes,Seconds,Hundredths);

   {Sort the list}
   TheList := mergesort(TheList,N);

   {Get the end time}
   GetTime(Hours2,Minutes2,Seconds2,Hundredths2);

   writeln('List Sorted');

   {Calculate the difference (I'm sure there's a better way)}
   Total := Hours * 360000 + Minutes * 6000 + Seconds * 100 + Hundredths;
   Total2 := Hours2 * 360000 + Minutes2 * 6000 + Seconds2 * 100 + Hundredths2;

   {Display Time taken}
   writeln('Approx Time Taken : ',Total2 - Total,' hundredths of a second');

   {Write the sorted list and the results to file}
   writeln('Writing Sorted list to File');
   writeln;
   append(OutFile);
   writeln(OutFile,'----- Sorted  List -----');
   writeln(OutFile);
   ShowList(TheList);
   writeln(OutFile,'Approx Time Taken : ',Total2 - Total,' hundredths of a second');
   close(OutFile);

end.

[Back to SORTING SWAG index]  [Back to Main SWAG index]  [Original]