我试图在Delphi中创建一个链表实现,但是无法创建节点,因为我需要检查头指针是否为空。我现在正在使用的代码如下所示:
procedure LinkedList.addNode(newNode: Node);
var lastNode: Node;
begin
if pHead = nil then
pHead := @newNode
else
lastNode := peekLastNode(pHead^);
lastNode.pNext := @newNode;
end;
仅添加一个元素,程序就会冻结,因此,无数部分是无限期的问题。
这里是整个程序:
program LinkedListImplementation;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
Node = record
data: string;
pNext: ^Node;
end;
type
LinkedList = class
pHead: ^Node;
function peekLastNode (currentNode: Node) : Node;
function listToString(currentNode: Node) : String;
procedure addNode (newNode: Node);
end;
//the initial parameter for this function is LinkedList.pHead^
function LinkedList.peekLastNode (currentNode: Node) : Node;
begin
if currentNode.pNext = nil then
result := currentNode
else
result := peekLastNode(currentNode.pNext^);
end;
//produces string in form 'abc -> def -> ghi' from linked list
function LinkedList.listToString(currentNode: Node) : String;
begin
if currentNode.pNext = nil then
result := currentNode.data
else
result := currentNode.data + ' -> ' + listToString(currentNode.pNext^)
end;
//this uses helper method 'peekLastNode'
procedure LinkedList.addNode(newNode: Node);
var lastNode: Node;
begin
if pHead = nil then
pHead := @newNode
else
lastNode := peekLastNode(pHead^);
lastNode.pNext := @newNode;
end;
var
Strings: LinkedList;
String1: Node;
String2: Node;
begin
try
String1.data := 'abc';
String2.data := 'def';
Strings.Create();
Strings.addNode(String1);
Strings.addNode(String2);
WriteLn(Strings.listToString(Strings.pHead^));
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
在addNode()
中,如果pHead
为nil
,则将其设置为指向局部变量,如果不是nil
,则将其设置为lastNode.pNext
指向另一个局部变量。当addNode()
退出时,这些局部变量将超出范围,从而使pHead
/ pNext
悬空,因此它们将在您下次尝试使用它们时指向无效的内存。
[将Node
实例添加到列表时,需要使用堆分配,并且需要传递^Node
指针,而不是直接传递Node
实例。
[此外,addNode()
具有逻辑错误,因为它无条件设置lastNode.pNext
是否为pHead
为nil
。如果pHead为nil
,则lastNode
未分配任何内容。 else
块在其操作周围缺少begin..end
语句。
而且,您甚至都没有正确构造LinkedList
对象。 Strings.Create();
必须为Strings := LinkedList.Create();
。
话虽如此,请尝试更多类似这样的事情:
program LinkedListImplementation;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
PNode = ^Node;
Node = record
data: string;
pNext: PNode;
end;
type
LinkedList = class
private
pHead: PNode;
public
destructor Destroy; override;
function peekLastNode(currentNode: PNode = nil): PNode;
function listToString(currentNode: PNode = nil): String;
function addNode(const data: String): PNode;
procedure clear;
end;
destructor LinkedList.Destroy;
begin
clear;
end;
//the initial parameter for this function is LinkedList.pHead
function LinkedList.peekLastNode(currentNode: PNode) : PNode;
begin
if currentNode = nil then currentNode := pHead;
if (currentNode = nil) or (currentNode.pNext = nil) then
Result := currentNode
else
Result := peekLastNode(currentNode.pNext);
end;
{ Alternatively:
function LinkedList.peekLastNode(currentNode: PNode): PNode;
begin
if currentNode = nil then currentNode := pHead;
Result := currentNode;
if Result <> nil then
begin
while Result.pNext <> nil do
Result := Result.pNext;
end;
end;
}
//produces string in form 'abc -> def -> ghi' from linked list
function LinkedList.listToString(currentNode: PNode): String;
begin
if currentNode = nil then currentNode := pHead;
if currentNode = nil then
Result := ''
else if currentNode.pNext = nil then
Result := currentNode.data
else
Result := currentNode.data + ' -> ' + listToString(currentNode.pNext);
end;
{ Alternatively:
function LinkedList.listToString(currentNode: PNode): String;
begin
Result := '';
if currentNode = nil then currentNode := pHead;
if currentNode <> nil then
begin
Result := currentNode.data;
while currentNode.pNext <> nil do
begin
currentNode := currentNode.pNext;
Result := Result + ' -> ' + currentNode.data;
end;
end;
end;
}
//this uses helper method 'peekLastNode'
function LinkedList.addNode(const data: String): PNode;
var
newNode, lastNode: PNode;
begin
New(newNode);
newNode.data := data;
newNode.pNext := nil;
if pHead = nil then
pHead := newNode
else begin
lastNode := peekLastNode(pHead);
lastNode.pNext := newNode;
end;
end;
{ Alternatively:
function LinkedList.addNode(const data: String): PNode;
var
currentNode: ^PNode;
begin
currentNode := @pHead;
while currentNode^ <> nil do
currentNode := @((currentNode^).pNext);
New(currentNode^);
(currentNode^).data := data;
(currentNode^).pNext := nil;
end;
}
procedure LinkedList.clear;
var
currentNode, nextNode: PNode;
begin
currentNode := pHead;
while currentNode <> nil do
begin
nextNode := currentNode.pNext;
Dispose(currentNode);
currentNode := nextNode;
end;
end;
var
Strings: LinkedList;
begin
try
Strings := LinkedList.Create();
try
Strings.addNode('abc');
Strings.addNode('def');
WriteLn(Strings.listToString());
finally
Strings.Free();
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
ReadLn;
end.