Spring 框架提供了豐富的集合型別,包括 IEnumerable<T>
、ICollection<T>
和 IList<T>
等介面,以及 TEnumerable
類別,方便開發者進行資料操作。IEnumerable<T>
介面提供基本的迭代功能,ICollection<T>
介面擴充套件了集合操作,而 IList<T>
介面則提供了更精細的列表操作,例如透過索引存取元素。TEnumerable
類別提供額外的工具函式,例如 Range
、Repeated
和 Empty
等,簡化常見的集合操作。理解這些介面和類別的差異,能幫助開發者選擇最合適的資料結構,提升程式碼效率。不同集合型別在存取、搜尋、插入和刪除操作上的時間複雜度各有不同,開發者需要根據實際需求選擇合適的資料結構。文章也詳細介紹了堆積疊、佇列和雙向佇列等特殊集合型別,並提供程式碼範例,說明如何在 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 = 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
##範例程式 以下是使用 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
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>
介面來實作堆積疊,該介面包含了 Push
、Pop
、Peek
等方法。
佇列(Queue)
佇列是一種先進先出的資料結構,意思是最先加入的資料最先被取出。佇列的基本操作包括:
- Enqueue:加入資料到佇列的尾部
- Dequeue:取出佇列頭部的資料
- Peek:檢視佇列頭部的資料而不取出
佇列可以用陣列或連結串列實作。Spring 框架提供了 IQueue<T>
介面來實作佇列,該介面包含了 Enqueue
、Dequeue
、Peek
等方法。
Spring 的實作
Spring 框架提供了 IStack<T>
和 IQueue<T>
介面來實作堆積疊和佇列。這些介面包含了基本的操作方法,例如 Push
、Pop
、Peek
等。
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
類別提供的擴充功能,例如Range
、Repeated
和Empty
等函式,更有助於開發者靈活運用這些資料結構。分析不同資料結構的特性,例如列表的有序性、集合的唯一性以及堆積疊和佇列的先進先出/後進先出特性,可以幫助開發者根據實際需求選擇合適的資料結構,並藉由理解其時間複雜度,進一步提升程式效能。然而,Spring 集合使用動態陣列實作堆積疊和佇列,雖然在效能上有所提升,但也需要開發者注意動態陣列擴充的潛在效能損耗。展望未來,隨著 Spring 框架的持續發展,預期會有更多針對特定應用場景的資料結構和演算法最佳化出現,例如更有效率的排序演算法和更靈活的集合操作。對於追求效能的開發者而言,深入理解 Spring 框架提供的各種資料結構和其底層實作原理,並根據應用場景選擇最合適的資料結構,將是提升應用程式效能的關鍵。玄貓認為,開發者應深入研究TEnumerable
類別,善用其提供的擴充功能,以簡化程式碼並提升開發效率。