home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1999 March
/
Chip_1999-03_cd.bin
/
zkuste
/
delphi
/
INFO
/
DI9810RS.ZIP
/
TOPO.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1998-05-01
|
9KB
|
306 lines
unit Topo;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
DependentPtr = ^Dependent;
ItemPtr = ^Item;
// A record to hold a pointer to a dependent item.
Dependent = record
DependentItem : ItemPtr; // The dependent item.
NextDependent : DependentPtr; // The next dependent Item.
end;
// A record to hold an item's dependencies.
Item = record
ItemValue : String[10]; // The item's name.
NumBefore : Integer; // # items before this one.
NextItem : ItemPtr; // Next item in the list.
PrevItem : ItemPtr; // Previous item in the list.
FirstDependent : DependentPtr; // First item after this one.
end;
TTopoSortForm = class(TForm)
memInputs: TMemo;
memOutputs: TMemo;
cmdSolve: TButton;
procedure cmdSolveClick(Sender: TObject);
procedure LoadData;
function FindItem(item_value : String) : ItemPtr;
procedure OrderData;
function MoveToReady(itm : ItemPtr) : ItemPtr;
// For debugging:
procedure ShowStructure;
private
{ Private declarations }
public
{ Public declarations }
end;
var
TopoSortForm: TTopoSortForm;
implementation
{$R *.DFM}
var
// Sentinels for Ready and NotReady lists.
NotReadyTop, NotReadyBottom : Item;
// Sentinels for items without prerequisites.
ReadyTop, ReadyBottom : Item;
// Calculate a complete ordering.
procedure TTopoSortForm.cmdSolveClick(Sender: TObject);
begin
// Clear the output.
memOutputs.Clear;
memOutputs.Refresh;
// Get the input data.
LoadData;
// Find a complete ordering.
OrderData;
end;
// Load the input data from the memInputs Memo control.
procedure TTopoSortForm.LoadData;
var
i, p : Integer;
the_line, dep_name, pre_name : String;
itm, dep_item, pre_item : ItemPtr;
new_dep : DependentPtr;
begin
// Initialize the doubly linked lists.
NotReadyTop.NextItem := @NotReadyBottom;
NotReadyTop.PrevItem := nil;
NotReadyBottom.PrevItem := @NotReadyTop;
NotReadyBottom.NextItem := nil;
NotReadyBottom.ItemValue := #255; // A big value.
ReadyTop.NextItem := @ReadyBottom;
ReadyTop.PrevItem := nil;
ReadyBottom.PrevItem := @ReadyTop;
ReadyBottom.NextItem := nil;
ReadyBottom.ItemValue := #255;
// Get the input data. Load all the items into
// the NotReady list.
for i := 0 to memInputs.Lines.Count - 1 do
begin
// Parse this line.
the_line := Trim(memInputs.Lines[i]);
if (the_line = '') then Continue;
p := Pos(' ', the_line);
pre_name := Trim(Copy(the_line, 1, p - 1));
dep_name := Trim(Copy(the_line, p + 2, Length(the_line)));
// Find the items.
pre_item := FindItem(pre_name);
dep_item := FindItem(dep_name);
// Add dep_item to pre_item's dependent list.
// pre_item < dep_item.
GetMem(new_dep, SizeOf(Dependent));
new_dep^.DependentItem := dep_item;
new_dep^.NextDependent := pre_item^.FirstDependent;
pre_item^.FirstDependent := new_dep;
dep_item.NumBefore := dep_item.NumBefore + 1;
end;
// Move items with no dependencies into the Ready list.
itm := NotReadyTop.NextItem;
while (itm <> @NotReadyBottom) do
begin
if (itm.NumBefore > 0) then
begin
// Leave this item in the NotReady list.
// Prepare to examine the next item.
itm := itm^.NextItem;
end else begin
// This item is ready for output.
// Move it to the Ready list.
itm := MoveToReady(itm);
end;
end; // End while (itm <> @NotReadyBottom) loop.
end;
// Return a pointer to this item in the NotReady sorted
// linked list. If the item is not present, insert it.
function TTopoSortForm.FindItem(item_value : String) : ItemPtr;
var
itm, new_item : ItemPtr;
begin
// Search the NotReady list.
itm := NotReadyTop.NextItem;
while (itm^.ItemValue < item_value) do
itm := itm^.NextItem;
// See if we found it.
if (itm^.ItemValue <> item_value) then
begin
// We did not. Add the item before itm.
GetMem(new_item, SizeOf(Item));
new_item^.ItemValue := item_value;
new_item^.NumBefore := 0;
new_item^.FirstDependent := nil;
new_item^.PrevItem := itm^.PrevItem;
new_item^.NextItem := itm;
itm^.PrevItem := new_item;
new_item^.PrevItem^.NextItem := new_item;
// Make itm point to the new item.
itm := new_item;
end;
Result := itm;
end;
// Find a complete ordering and display it in memOutputs.
procedure TTopoSortForm.OrderData;
var
itm, dep_item : ItemPtr;
dep : DependentPtr;
begin
// While there are items in the Ready list, output one.
while (ReadyTop.NextItem <> @ReadyBottom) do
begin
// Remove the first item from the Ready list.
itm := ReadyTop.NextItem;
ReadyTop.NextItem := itm^.NextItem;
ReadyTop.NextItem^.PrevItem := @ReadyTop;
// Add the item to the output.
memOutputs.Lines.Add(itm^.ItemValue);
// Decrement NumBefore for all items that are
// dependent on this one.
dep := itm^.FirstDependent;
while (dep <> nil) do
begin
dep_item := dep^.DependentItem;
dep_item^.NumBefore := dep_item^.NumBefore - 1;
if (dep_item^.NumBefore < 1) then
begin
// This item has no more dependents.
// Move it to the Ready list.
MoveToReady(dep_item);
end;
// Free this Dependent record.
itm^.FirstDependent := dep^.NextDependent;
FreeMem(dep);
// Go to itm's next Dependent record.
dep := itm^.FirstDependent;
end; // End while (dep <> nil) loop.
end; // End while there are items in the Ready list.
// If there are still items in the NotReadyList, they
// cannot be ordered.
if (NotReadyTop.NextItem <> @NotReadyBottom) then
begin
memOutputs.Lines.Add('');
memOutputs.Lines.Add('Mutually dependent:');
while (NotReadyTop.NextItem <> @NotReadyBottom) do
begin
// Remove the first item from the NotReady list.
itm := NotReadyTop.NextItem;
NotReadyTop.NextItem := itm^.NextItem;
// Add the item to the output.
memOutputs.Lines.Add(itm^.ItemValue);
// Remove the dependents for itm.
dep := itm^.FirstDependent;
while (dep <> nil) do
begin
// Free this Dependent record.
itm^.FirstDependent := dep^.NextDependent;
FreeMem(dep);
// Go to itm's next Dependent record.
dep := itm^.FirstDependent;
end;
end; // End while NotReady list is not empty.
end; // End if there are items still in the NotReady list.
end;
// Move the indicated item to the Ready list. Leave itm
// pointing to the next item in the original list.
function TTopoSortForm.MoveToReady(itm : ItemPtr) : ItemPtr;
var
after_me, before_me : ItemPtr;
begin
// This item is ready for output.
after_me := itm^.PrevItem;
before_me := itm^.NextItem;
// Remove itm from the NotReadyList.
after_me^.NextItem := before_me;
before_me^.PrevItem := after_me;
// Add itm to the Ready list.
itm^.PrevItem := @ReadyTop;
itm^.NextItem := ReadyTop.NextItem;
itm^.NextItem^.PrevItem := itm;
ReadyTop.NextItem := itm;
// Return the item after itm in its original list.
Result := before_me;
end;
// This routine presents a message box displaying the
// data structure's current configuration. It is useful
// for showing what the data looks like ad the program
// progresses and helps with debugging.
procedure TTopoSortForm.ShowStructure;
var
txt : String;
itm : ItemPtr;
dep : DependentPtr;
begin
txt := 'Ready: ' + #10 + #13;
itm := ReadyTop.NextItem;
while (itm <> @ReadyBottom) do
begin
txt := txt + itm^.ItemValue +
'(' + IntToStr(itm^.NumBefore) + ')' + #10 + #13;
dep := itm^.FirstDependent;
while (dep <> nil) do
begin
txt := txt + ' ' + dep^.DependentItem^.ItemValue + #10 + #13;
dep := dep^.NextDependent;
end;
itm := itm^.NextItem;
end;
txt := txt + #10 + #13 + 'Not Ready: ' + #10 + #13;
itm := NotReadyTop.NextItem;
while (itm <> @NotReadyBottom) do
begin
txt := txt + itm^.ItemValue +
'(' + IntToStr(itm^.NumBefore) + ')' + #10 + #13;
dep := itm^.FirstDependent;
while (dep <> nil) do
begin
txt := txt + ' ' + dep^.DependentItem^.ItemValue + #10 + #13;
dep := dep^.NextDependent;
end;
itm := itm^.NextItem;
end;
ShowMessage(txt);
end;
end.