I am coming back to Pascal after years away, and one of my projects needs a number of linked lists. I checked all the books I had, some of them recent, and most showed how to make a LL with records and pointers. One of them has a class but the data is still a record so pointers needed.
However, looking at something else I realised that using only OOP could make this much simpler and not use visible pointers. So I searched and couldn't find anything, then resorted to asking Google AI. It came up with this solution (which I have edited slightly to make it into a program).
program linked_list_ai;
type
TNode = class
public
Data: Integer;
Next: TNode;
constructor Create(AValue: Integer);
end;
TLinkedList = class
private
FHead: TNode;
public
constructor Create;
destructor Destroy; override;
procedure Add(AValue: Integer);
procedure Display;
end;
constructor TNode.Create(AValue: Integer);
begin
Data := AValue;
Next := nil;
end;
constructor TLinkedList.Create;
begin
FHead := nil;
end;
// Destructor ensures all nodes are freed to prevent memory leaks
destructor TLinkedList.Destroy;
var
Temp: TNode;
begin
while FHead <> nil do
begin
Temp := FHead;
FHead := FHead.Next;
Temp.Free;
end;
inherited;
end;
// Method to add a new node to the end of the list
procedure TLinkedList.Add(AValue: Integer);
var
NewNode, Temp: TNode;
begin
NewNode := TNode.Create(AValue);
if FHead = nil then
FHead := NewNode
else
begin
Temp := FHead;
while Temp.Next <> nil do
Temp := Temp.Next;
Temp.Next := NewNode;
end;
end;
procedure TLinkedList.Display;
var
Temp: TNode;
begin
Temp := FHead;
while Temp <> nil do
begin
Write(Temp.Data, ' -> ');
Temp := Temp.Next;
end;
Writeln('NIL');
end;
var
MyList: TLinkedList;
begin
MyList := TLinkedList.Create;
try
MyList.Add(10);
MyList.Add(20);
MyList.Add(30);
MyList.Display;
finally
MyList.Free; // Calls the destructor and cleans up memory
end;
writeln('Press ENTER to continue...');
readln;
end.
For my purposes which has much more data I needed to be able to scan through the list and extract the data. The only change I needed to make was to make the FHead public (and modified Add to be Append and added an Insert method which allowed insertion into the front of the list). I put this into a Unit for convenience, then wrote some code to work through it as I wanted:
program linked_list_class;
{$mode objfpc}{$H+}
uses
crt, LinkedList;
var
nodes: TLinkedList;
node : TNode;
begin
ClrScr;
nodes := TLinkedList.Create; { start with an empty list }
try
nodes.Append(10);
nodes.Append(20);
nodes.Append(30);
nodes.Display;
{ Test working through the list }
if nodes.Empty then
writeln('Nodes list is empty!')
else
begin
node := nodes.FHead; {I can probably change this to get FHead? }
while node <> nil do
begin
{ I could change Data here with FHead exposed }
write(node.Data, ' => ');
node := node.Next;
end;
writeln('NIL');
end;
finally
nodes.Free;
end;
writeln;
Writeln('Done. Press Enter to exit...');
Readln;
end.
I just though this might be useful to others. You don't have to use ^ but refer to instances instead. You have to Free these of course, but the syntax seems much tidier.