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類別,善用其提供的擴充功能,以簡化程式碼並提升開發效率。