delphi寫一個 LinkedList,泛型容器,方便從中間刪除

del88發表於2024-12-09

在 Delphi 中,建立一個泛型連結串列(LinkedList)容器需要定義節點類和連結串列管理類,並確保它們都是泛型的,以便可以儲存任何型別的元素。以下是一個簡單的泛型連結串列實現,它包括節點類 TLinkedListNode<T> 和連結串列管理類 TLinkedList<T>。這個實現支援從中間刪除元素。

unit Generic.LinkedList;

interface

uses
  System.SysUtils, System.Generics.Collections;

type
  // 節點類,泛型 T 表示節點儲存的資料型別
  TLinkedListNode<T> = class
  private
    FData: T;
    FNext: TLinkedListNode<T>;
  public
    constructor Create(const AData: T);
    property Data: T read FData write FData;
    property Next: TLinkedListNode<T> read FNext write FNext;
  end;

  // 連結串列類,泛型 T 表示連結串列儲存的資料型別
  TLinkedList<T> = class
  private
    FHead: TLinkedListNode<T>;
    FTail: TLinkedListNode<T>;
    FCount: Integer;
    function GetNodeAt(AIndex: Integer): TLinkedListNode<T>;
  public
    constructor Create;
    destructor Destroy; override;
    
    // 新增元素到連結串列末尾
    procedure Add(const AData: T);
    
    // 從連結串列中刪除指定索引處的元素
    procedure Delete(AIndex: Integer);
    
    // 獲取連結串列中元素的數量
    function Count: Integer;
    
    // 獲取或設定指定索引處的元素
    property Items[AIndex: Integer]: T read GetNodeAt.Data write GetNodeAt.Data; default;
  end;

implementation

{ TLinkedListNode<T> }

constructor TLinkedListNode<T>.Create(const AData: T);
begin
  FData := AData;
  FNext := nil;
end;

{ TLinkedList<T> }

constructor TLinkedList<T>.Create;
begin
  FHead := nil;
  FTail := nil;
  FCount := 0;
end;

destructor TLinkedList<T>.Destroy;
var
  Current, Temp: TLinkedListNode<T>;
begin
  Current := FHead;
  while Current <> nil do
  begin
    Temp := Current;
    Current := Current.Next;
    Temp.Free;
  end;
  inherited;
end;

procedure TLinkedList<T>.Add(const AData: T);
var
  NewNode: TLinkedListNode<T>;
begin
  NewNode := TLinkedListNode<T>.Create(AData);
  if FTail <> nil then
  begin
    FTail.Next := NewNode;
  end
  else
  begin
    FHead := NewNode;
  end;
  FTail := NewNode;
  Inc(FCount);
end;

procedure TLinkedList<T>.Delete(AIndex: Integer);
var
  Current, Previous: TLinkedListNode<T>;
begin
  if (AIndex < 0) or (AIndex >= FCount) then
    raise Exception.Create('Index out of bounds');

  Current := FHead;
  if AIndex = 0 then
  begin
    FHead := Current.Next;
    if FHead = nil then
      FTail := nil;
    Current.Free;
  end
  else
  begin
    Previous := nil;
    while AIndex > 0 do
    begin
      Previous := Current;
      Current := Current.Next;
      Dec(AIndex);
    end;
    Previous.Next := Current.Next;
    if Previous.Next = nil then
      FTail := Previous;
    Current.Free;
  end;
  Dec(FCount);
end;

function TLinkedList<T>.Count: Integer;
begin
  Result := FCount;
end;

function TLinkedList<T>.GetNodeAt(AIndex: Integer): TLinkedListNode<T>;
var
  Current: TLinkedListNode<T>;
  I: Integer;
begin
  if (AIndex < 0) or (AIndex >= FCount) then
    raise Exception.Create('Index out of bounds');

  Current := FHead;
  for I := 0 to AIndex - 1 do
  begin
    Current := Current.Next;
  end;
  Result := Current;
end;

end.

這個實現包括了以下功能:

  • TLinkedListNode<T>:表示連結串列中的一個節點,包含資料和指向下一個節點的指標。
  • TLinkedList<T>:表示連結串列本身,管理節點的新增、刪除和訪問。
  • Add 方法:在連結串列末尾新增一個新元素。
  • Delete 方法:從連結串列中刪除指定索引處的元素。如果索引是 0,則刪除頭節點;否則,遍歷連結串列找到要刪除的節點,並調整前一個節點的 Next 指標。
  • Count 方法:返回連結串列中元素的數量。
  • Items 屬性:允許透過索引訪問連結串列中的元素。這是透過 GetNodeAt 方法實現的,該方法根據索引返回對應的節點。

請注意,這個實現沒有處理併發訪問或執行緒安全問題。如果你需要在多執行緒環境中使用連結串列,請新增適當的同步機制。此外,這個連結串列是單向的,如果你需要雙向連結串列,可以相應地擴充套件節點類和連結串列類。

相關文章