Contributor: GUY MCLOUGHLIN           


program Demo_Doubly_Linked_List_Sort;

const
  co_MaxNode = 1000;

type
  T_St15   = string[15];

  T_PoNode = ^T_Node;

  T_Node   = record
               Data : T_St15;
               Next,
               Prev : T_PoNode
             end;

  T_PoArNodes  = ^T_ArNodePtrs;
  T_ArNodePtrs = array[1..succ(co_MaxNode)] of T_PoNode;


  function RandomString : {output}
                           T_St15;
  var
    by_Index : byte;
    st_Temp  : T_St15;
  begin
    st_Temp[0] := chr(succ(random(15)));
    for by_Index := 1 to length(st_Temp) do
      st_Temp[by_Index] := chr(random(26) + 65);
    RandomString := st_Temp
  end;

  procedure AddNode({update}
                     var
                       po_Node : T_PoNode);
  begin
    if (maxavail > sizeof(T_Node)) then
      begin
        new(po_Node^.Next);
        po_Node^.Next^.Next := nil;
        po_Node^.Next^.Prev := po_Node;
        po_Node^.Next^.Data := RandomString
      end
  end;

  procedure DisplayList({input}
                         po_Node : T_PoNode);
  var
    po_Temp : T_PoNode;
  begin
    po_Temp := po_Node;
    repeat
      write(po_Temp^.Data:20);
      po_Temp := po_Temp^.Next
    until (po_Temp^.Next = nil);
    write(po_Temp^.Data:20)
  end;

  procedure ShellSortNodes ({update}
                             var
                               ar_Nodes   : T_ArNodePtrs;
                            {input }
                             wo_NodeTotal : word);
  var
    Temp   : T_PoNode;
    Index1,
    Index2,
    Index3 : word;
  begin
    Index3 := 1;
    repeat
      Index3 := succ(3 * Index3)
    until (Index3 > wo_NodeTotal);
    repeat
      Index3 := (Index3 div 3);
      for Index1 := succ(Index3) to wo_NodeTotal do
        begin
          Temp := ar_Nodes[Index1];
          Index2 := Index1;
          while (ar_Nodes[(Index2 - Index3)]^.Data > Temp^.Data) do
            begin
              ar_Nodes[Index2] := ar_Nodes[(Index2 - Index3)];
              Index2 := (Index2 - Index3);
              if (Index2 <= Index3) then
                break
            end;
          ar_Nodes[Index2] := Temp
        end
    until (Index3 = 1)
  end;        (* ShellSortNodes.                                      *)

  procedure RebuildList({input }
                         var
                           ar_Nodes : T_ArNodePtrs;
                        {update}
                         var
                           po_Head  : T_PoNode);
  var
    wo_Index   : word;
    po_Current : T_PoNode;
  begin
    wo_Index := 1;
    po_Head := ar_Nodes[wo_Index];
    po_Head^.Prev := nil;
    po_Head^.Next := ar_Nodes[succ(wo_Index)];
    po_Current := po_Head;
    repeat
      inc(wo_Index);
      po_Current := po_Current^.Next;
      po_Current^.Next := ar_Nodes[succ(wo_Index)];
      po_Current^.Prev := ar_Nodes[pred(wo_Index)]
    until (ar_Nodes[succ(wo_Index)] = nil)
  end;

var
  wo_Index    : word;

  po_Heap     : pointer;

  po_Head,
  po_Current   : T_PoNode;

  po_NodeArray : T_PoArNodes;

BEGIN
              (* Initialize pseudo-random number generator.           *)
  randomize;

              (* Mark initial HEAP state.                             *)
  mark(po_Heap);

              (* Initialize list head node.                           *)
  new(po_Head);
  with po_Head^ do
    begin
      Next := nil;
      Prev := nil;
      Data := RandomString
    end;

              (* Create doubly linked list of random strings.         *)
  po_Current := po_Head;
  for wo_Index := 1 to co_MaxNode do
    begin
      AddNode(po_Current);
      if (wo_Index < co_MaxNode) then
        po_Current := po_Current^.Next
    end;

  writeln('Total Nodes = ', wo_Index);
  readln;

  DisplayList(po_Head);
  writeln;
  writeln;

              (* Allocate array of node pointers on the HEAP.         *)
  if (maxavail > sizeof(T_ArNodePtrs)) then
    new(po_NodeArray);

              (* Set them all to NIL.                                 *)
  fillchar(po_NodeArray^, sizeof(po_NodeArray^), 0);

              (* Assign pointer in array to nodes.                    *)
  wo_Index := 0;
  po_Current := po_Head;
  repeat
    inc(wo_Index);
    po_NodeArray^[wo_Index] := po_Current;
    po_Current := po_Current^.Next
  until (po_Current^.Next = nil);

              (* ShellSort the array of nodes.                        *)
  ShellSortNodes(po_NodeArray^, wo_Index);

              (* Re-build the doubly linked-list from array of nodes. *)
  RebuildList(po_NodeArray^, po_Head);

              (* Deallocate array of nodes.                           *)
  dispose(po_NodeArray);

  writeln;
  writeln;
  DisplayList(po_Head);

              (* Release HEAP memory used.                            *)
  release(po_Heap)

END.