Spring 框架提供了豐富的集合型別,包括 IEnumerable<T>ICollection<T>IList<T> 等介面,以及 TEnumerable 類別,方便開發者進行資料操作。IEnumerable<T> 介面提供基本的迭代功能,ICollection<T> 介面擴充套件了集合操作,而 IList<T> 介面則提供了更精細的列表操作,例如透過索引存取元素。TEnumerable 類別提供額外的工具函式,例如 RangeRepeatedEmpty 等,簡化常見的集合操作。理解這些介面和類別的差異,能幫助開發者選擇最合適的資料結構,提升程式碼效率。不同集合型別在存取、搜尋、插入和刪除操作上的時間複雜度各有不同,開發者需要根據實際需求選擇合適的資料結構。文章也詳細介紹了堆積疊、佇列和雙向佇列等特殊集合型別,並提供程式碼範例,說明如何在 Spring 框架中使用這些資料結構。

列舉、集合和列表

在 Spring 框架中,列舉、集合和列表是三種常見的資料結構。這些資料結構提供了不同的方法來儲存和運算元據。

列舉(IEnumerable

列舉是一種可以遍歷的集合,允許您逐一存取其元素。Spring 框架提供了 IEnumerable<T> 介面來表示列舉。

IEnumerable<T> = interface
  function GetEnumerator: IEnumerator<T>;
end;

IEnumerable<T> 介面提供了 GetEnumerator 方法,傳回一個 IEnumerator<T> 物件,用於遍歷集合中的元素。

集合(ICollection

集合是一種無序的元素集合,允許您新增、移除和查詢元素。Spring 框架提供了 ICollection<T> 介面來表示集合。

ICollection<T> = interface(IEnumerable<T>)
  function Add(const item: T): Boolean;
  procedure AddRange(const values: array of T);
  function Extract(const item: T): T;
  procedure Clear;
  function CopyTo(var values: TArray<T>; index: Integer): Integer;
  function MoveTo(const collection: ICollection<T>): Integer;
  function Remove(const item: T): Boolean;
  function RemoveAll(const predicate: Predicate<T>): Integer;
  property OnChanged: ICollectionChangedEvent<T> read GetOnChanged;
end;

ICollection<T> 介面提供了多種方法來操作集合,包括新增、移除、清除和複製元素。

列表(IList

列表是一種有序的元素集合,允許您存取和操作元素。Spring 框架提供了 IList<T> 介面來表示列表。

IList<T> = interface(ICollection<T>)
  function IndexOf(const item: T): Integer;
  procedure Insert(index: Integer; const item: T);
  procedure RemoveAt(index: Integer);
  property Items[index: Integer]: T read GetItem write SetItem;
end;

IList<T> 介面提供了多種方法來操作列表,包括存取和修改元素。

示例

以下示例展示瞭如何使用 IEnumerable<T>ICollection<T>IList<T> 介面:

var
  list: IList<Integer>;
begin
  list := IList<Integer>.Create;
  list.Add(1);
  list.Add(2);
  list.Add(3);
  
  // 使用 IEnumerable<T> 遍歷集合
  for item in list do
    Writeln(item);
  
  // 使用 ICollection<T> 新增和移除元素
  list.Add(4);
  list.Remove(2);
  
  // 使用 IList<T> 存取和修改元素
  Writeln(list[0]); // 輸出:1
  list[0] := 10;
  Writeln(list[0]); // 輸出:10
end;

這個示例展示瞭如何使用不同的介面來操作集合和列表。

列表和集合的使用

在 Spring 中,列表和集合是非常重要的資料結構。這些資料結構可以用來儲存和管理大量的資料。下面,我們將介紹如何使用 Spring 的列表和集合。

列表

Spring 的列表是實作了 IList<T> 介面的類別。列表可以儲存多個元素,並且可以對元素進行增加、刪除、修改等操作。

var
  list: IList<integer>;
begin
  list := TCollections.CreateList<integer>;
  list.Add(1);
  list.Add(2);
  list.Add(3);
  ListBox1.Items.Add('List: ' + Join(' ', list.ToArray));
end;

排序列表

排序列表是實作了 IList<T> 介面的類別,並且可以自動排序元素。排序列表可以用來儲存需要排序的資料。

var
  sortedList: IList<integer>;
begin
  sortedList := TCollections.CreateSortedList<integer>;
  sortedList.Add(3);
  sortedList.Add(1);
  sortedList.Add(2);
  ListBox1.Items.Add('Sorted List: ' + Join(' ', sortedList.ToArray));
end;

字典

字典是實作了 IDictionary<TKey, TValue> 介面的類別。字典可以儲存鍵值對,並且可以用鍵來查詢值。

var
  dictionary: IDictionary<string, integer>;
begin
  dictionary := TCollections.CreateDictionary<string, integer>;
  dictionary.Add('one', 1);
  dictionary.Add('two', 2);
  ListBox1.Items.Add('Dictionary: ' + dictionary['one'].ToString);
end;

集合

集合是實作了 ISet<T> 介面的類別。集合可以儲存唯一的元素,並且可以用來查詢元素是否存在於集合中。

var
  set: ISet<integer>;
begin
  set := TCollections.CreateSet<integer>;
  set.Add(1);
  set.Add(2);
  set.Add(2);
  ListBox1.Items.Add('Set: ' + Join(' ', set.ToArray));
end;

堆積疊和佇列

堆積疊和佇列是實作了 IStack<T>IQueue<T> 介面的類別。堆積疊是後進先出的資料結構,佇列是先進先出的資料結構。

var
  stack: IStack<integer>;
  queue: IQueue<integer>;
begin
  stack := TCollections.CreateStack<integer>;
  stack.Push(1);
  stack.Push(2);
  ListBox1.Items.Add('Stack: ' + stack.Pop.ToString);

  queue := TCollections.CreateQueue<integer>;
  queue.Enqueue(1);
  queue.Enqueue(2);
  ListBox1.Items.Add('Queue: ' + queue.Dequeue.ToString);
end;

雙端佇列

雙端佇列是實作了 IDeque<T> 介面的類別。雙端佇列可以在兩端增加和刪除元素。

var
  deque: IDeque<integer>;
begin
  deque := TCollections.CreateDeque<integer>;
  deque.AddFirst(1);
  deque.AddLast(2);
  ListBox1.Items.Add('Deque: ' + Join(' ', deque.ToArray));
end;

時間複雜度

下面是 Spring 集合的時間複雜度:

集合 存取 搜尋 插入 刪除
列表 O(1) O(n) O(n) O(n)
排序列表 O(1) O(log n) O(log n) O(n)
字典 O(1) O(1) O(1) O(1)
集合 O(1) O(1) O(1) O(1)
堆積疊 O(1) O(n) O(1) O(1)
佇列 O(1) O(n) O(1) O(1)
雙端佇列 O(1) O(n) O(1) O(1)

注意:時間複雜度可能會根據具體情況而有所不同。

TEnumerable 類別

在探索其他資料結構之前,我們需要先了解 TEnumerable 類別。TEnumerable 類別實作了一些有用的操作,包括重複的操作和不在 IEnumerable 介面中的操作。以下是 TEnumerable 類別的精簡版本,包含了一些有趣的功能:

TEnumerable = class
  class function Chunk<T>(const source: IEnumerable<T>; size: Integer): IEnumerable<TArray<T>>;
  class function Distinct<T>(const source: IEnumerable<T>): IEnumerable<T>;
  class function DistinctBy<T, TKey>(const source: IEnumerable<T>; const keySelector: Func<T, TKey>): IEnumerable<T>;
  class function Empty<T>: IReadOnlyList<T>;
  class function From<T>(const values: array of T): IReadOnlyList<T>;
  class function Intersect<T>(const first, second: IEnumerable<T>): IEnumerable<T>;
  class function Range(start, count: Integer): IReadOnlyList<Integer>;
  class function Repeated<T>(const element: T; count: Integer): IEnumerable<T>;
  class function Select<T, TResult>(const source: IEnumerable<T>; const selector: Func<T, TResult>): IEnumerable<TResult>;
  class function Union<T>(const first, second: IEnumerable<T>): IEnumerable<T>;
end;

已經使用過的 Range 函式可以用於產生一系列數字。Repeated 函式可以重複一個元素,Empty 函式可以傳回一個空的唯讀列表。

##範例程式 以下是使用 TEnumerable 類別的範例程式:

procedure TfrmTEnumerable.btnTEnumerable1Click(Sender: TObject);
var
  list: TList<Integer>;
begin
  list := TList<Integer>.Create(TEnumerable.Range(11, 9).ToArray);
  ListBox1.Items.Add('Range(11,9): ' + Join(' ', TEnumerable.From<Integer>(list)));
  list.Free;
end;

在這個範例中,使用 TEnumerable.Range 函式產生了一系列數字,然後使用 TEnumerable.From 函式將 Delphi 的 TList 物件轉換為 Spring 的 IEnumerable 介面。

Join 函式

Join 函式可以用於將一個集合轉換為一個字串。以下是 Join 函式的實作:

function TfrmTEnumerable.Join(const delim: string; const enum: IEnumerable<Integer>): string;
begin
  Result := string.Join(delim, TEnumerable.Select<Integer, string>(enum, IntToString).ToArray);
end;

function TfrmTEnumerable.IntToString(const val: Integer): string;
begin
  Result := IntToStr(val);
end;

在這個實作中,使用 TEnumerable.Select 函式將集合轉換為一個字串集合,然後使用 string.Join 函式將字串集合轉換為一個單一的字串。

堆積疊和佇列

Spring 集合實作了三種基礎的集合型別:堆積疊(LIFO)、佇列(FIFO)和雙端佇列(deque)。雖然佇列和堆積疊通常使用連結串列實作,但 Spring 集合使用動態陣列實作。這種方法更快,因為不需要頻繁地分配小的記憶體塊。

堆積疊和佇列介紹

堆積疊(Stack)和佇列(Queue)是兩種基本的資料結構,常用於管理和操作資料。

堆積疊(Stack)

堆積疊是一種後進先出的資料結構,意思是最後加入的資料最先被取出。堆積疊的基本操作包括:

  • Push:加入資料到堆積疊的頂部
  • Pop:取出堆積疊頂部的資料
  • Peek:檢視堆積疊頂部的資料而不取出

堆積疊可以用陣列或連結串列實作。Spring 框架提供了 IStack<T> 介面來實作堆積疊,該介面包含了 PushPopPeek 等方法。

佇列(Queue)

佇列是一種先進先出的資料結構,意思是最先加入的資料最先被取出。佇列的基本操作包括:

  • Enqueue:加入資料到佇列的尾部
  • Dequeue:取出佇列頭部的資料
  • Peek:檢視佇列頭部的資料而不取出

佇列可以用陣列或連結串列實作。Spring 框架提供了 IQueue<T> 介面來實作佇列,該介面包含了 EnqueueDequeuePeek 等方法。

Spring 的實作

Spring 框架提供了 IStack<T>IQueue<T> 介面來實作堆積疊和佇列。這些介面包含了基本的操作方法,例如 PushPopPeek 等。

Spring 的堆積疊和佇列實作提供了多種工廠方法來建立堆積疊和佇列例項,例如 CreateStack<T>CreateQueue<T>

範例程式

以下是使用 Spring 框架的 IStack<T> 介面實作的一個簡單堆積疊範例:

var
  stack: IStack<string>;
  ch: char;
  s: string;
begin
  stack := TCollections.CreateStack<string>;
  
  for ch := '1' to '7' do
    stack.Push(ch);
  
  ListBox1.Items.Add('Stack: ' + ''.Join(' ', stack.ToArray));
  
  s := 'Stack remove: ';
  while not stack.IsEmpty do
    s := s + stack.Pop + ' ';
  
  ListBox1.Items.Add(s);
end;

這個範例建立了一個字串堆積疊,然後將字元 ‘1’ 到 ‘7’ 推入堆積疊。接著,它將堆積疊的內容加入到列表框中,然後將所有字串從堆積疊中彈出並加入到列表框中。

介紹資料結構中的Queue

Queue是一種先進先出的資料結構,元素從尾部加入,從頭部移除。Spring框架中實作了三種Queue變體:正常Queue、有界Queue和逐出Queue。

Queue介面

Queue介面定義了以下方法:

  • Clear: 清除Queue中的所有元素
  • Enqueue(const item: T): Boolean: 將元素加入Queue尾部
  • Dequeue: T: 移除Queue頭部的元素
  • Extract: T: 移除Queue頭部的元素
  • Peek: T: 檢視Queue頭部的元素
  • PeekOrDefault: T: 檢視Queue頭部的元素,如果Queue為空則傳回預設值
  • TryDequeue(var item: T): Boolean: 嘗試移除Queue頭部的元素
  • TryExtract(var item: T): Boolean: 嘗試移除Queue頭部的元素
  • TryPeek(var item: T): Boolean: 嘗試檢視Queue頭部的元素
  • TrimExcess: 刪除Queue中多餘的空間

Queue的種類

Spring框架中實作了三種Queue變體:

  • 正常Queue:無大小限制
  • 有界Queue:有大小限制,當Queue滿時,新加入的元素會被丟棄
  • 逐出Queue:有大小限制,當Queue滿時,Queue頭部的元素會被丟棄

Queue的使用

Queue可以使用以下方法進行操作:

// 建立一個Queue
queue := TCollections.CreateQueue<string>;

// 將元素加入Queue尾部
for ch := '1' to '7' do
  queue.Enqueue(ch);

// 檢視Queue頭部的元素
s := 'Queue remove: ';
while not queue.IsEmpty do
  s := s + queue.Dequeue + ' ';

// 刪除Queue中多餘的空間
queue.TrimExcess;

有界Queue和逐出Queue的使用

有界Queue和逐出Queue可以使用以下方法進行操作:

// 建立一個有界Queue
queue := TCollections.CreateBoundedQueue<string>(5);

// 將元素加入Queue尾部
for ch := '1' to '7' do
  queue.Enqueue(ch);

// 檢視Queue頭部的元素
ListBox1.Items.Add('BoundedQueue: ' + ''.Join(' ', queue.ToArray));

// 建立一個逐出Queue
queue := TCollections.CreateEvictingQueue<string>(5);

// 將元素加入Queue尾部
for ch := '1' to '7' do
  queue.Enqueue(ch);

// 檢視Queue頭部的元素
ListBox1.Items.Add('EvictingQueue: ' + ''.Join(' ', queue.ToArray));

雙向佇列(Deque)概述

雙向佇列(Deque)是一種可以在兩端新增和移除元素的集合。它類似於佇列,但提供了更多的操作方式。下面是 Spring 中的 IDeque<T> 介面定義:

IDeque<T> = interface(IEnumerable<T>)
  procedure Clear;
  function AddFirst(const item: T): Boolean;
  function AddLast(const item: T): Boolean;
  function RemoveFirst: T;
  function RemoveLast: T;
  function ExtractFirst: T;
  function ExtractLast: T;
  function TryRemoveFirst(var item: T): Boolean;
  function TryRemoveLast(var item: T): Boolean;
  function TryExtractFirst(var item: T): Boolean;
  function TryExtractLast(var item: T): Boolean;
  procedure TrimExcess;
  property Capacity: Integer read GetCapacity write SetCapacity;
  property OnChanged: ICollectionChangedEvent<T> read GetOnChanged;
end;

這個介面提供了多種方法來操作雙向佇列,包括新增和移除元素、清空集合、以及取得集合的容量和變化事件。

雙向佇列的實作

Spring 提供了三種不同的雙向佇列實作:正常的雙向佇列、有界的雙向佇列和逐出式的雙向佇列。這些實作可以透過工廠方法來建立:

class function CreateDeque<T>: IDeque<T>;
class function CreateBoundedDeque<T>(size: Integer): IDeque<T>;
class function CreateEvictingDeque<T>(size: Integer): IDeque<T>;

正常的雙向佇列的大小不受限制,而有界的雙向佇列和逐出式的雙向佇列則有最大大小限制。當有界的雙向佇列達到最大大小時,新的元素將被丟棄;而逐出式的雙向佇列則會移除另一端的元素。

從資料結構的底層實作到高階應用,本文全面檢視了 Spring 框架中列舉、集合、列表、堆積疊、佇列和雙向佇列等關鍵資料結構。藉由程式碼範例和介面定義的解析,我們深入探討了IEnumerable<T>ICollection<T>IList<T>IStack<T>IQueue<T>IDeque<T>等核心介面的使用方法,以及TEnumerable類別提供的擴充功能,例如RangeRepeatedEmpty等函式,更有助於開發者靈活運用這些資料結構。分析不同資料結構的特性,例如列表的有序性、集合的唯一性以及堆積疊和佇列的先進先出/後進先出特性,可以幫助開發者根據實際需求選擇合適的資料結構,並藉由理解其時間複雜度,進一步提升程式效能。然而,Spring 集合使用動態陣列實作堆積疊和佇列,雖然在效能上有所提升,但也需要開發者注意動態陣列擴充的潛在效能損耗。展望未來,隨著 Spring 框架的持續發展,預期會有更多針對特定應用場景的資料結構和演算法最佳化出現,例如更有效率的排序演算法和更靈活的集合操作。對於追求效能的開發者而言,深入理解 Spring 框架提供的各種資料結構和其底層實作原理,並根據應用場景選擇最合適的資料結構,將是提升應用程式效能的關鍵。玄貓認為,開發者應深入研究TEnumerable類別,善用其提供的擴充功能,以簡化程式碼並提升開發效率。