Delphi 运行时库RTL数据结构
同事们,一天一节,细水长流......
EMB官方性能测试与比较WPF、Electron的指标的测试源码:https://github.com/Embarcadero/ComparisonResearch/tree/main/calculator
序
大部分存储在System.Classes和System.Generics.Collection单元中,能大大简化日常工作。
是专门设计用来存储和检索数据的类。
世界上的每个数据结构都在寻求四种不同类型的数据处理之间的平衡:修改数据、插入数据、搜索数据和删除数据。有些数据结构在某些领域很好,有些在 另外的领域很好,但是这个世界上没有任何数据结构能够做到使上述所有这四种操作与数据的(记录等)大小无关,也不能在某种数据增长趋势下同时保证上述4种数据处理达到同样优异的性能。
在设计一个程序时,我们应该知道我们的需求是什么。这将帮助我们为程序的设计选择适当的数据结构。
Delphi可用于处理字符串的数据结构的性能
案例:github\Delphi-High-Performance\Chapter 1\RandomWordSearch.dproj
数据结构 | 对数据的操作 | 大O平均时间复杂度 | 最糟糕的情况 | 备注 |
TStringList | Direct Access | O(1) | TStringList提供了两种工作模式:未排序和排序,前者是默认的。 | |
Add | O(1)/O(log n) | 未排序模式下,能有很好的性能;反之会很糟糕 | ||
Insert | O(1) | |||
Delete | O(1) | |||
IndexOf | O(n)/O(log n) | 二分法:找到索引的位置;在有序模式下,是最适合二分法的。 | ||
Sort | O(n log n) | 排序模式下,能有很好的性能;反之会很糟糕:因为它首先套IndexOf找位置。 | ||
TDictionary | Direct Access | 不能直接访问,只能用间接方法遍历元素 | 1、TDictionary不能这样访问元素TDictionary[i];只能类似for in do的方式遍历出元素; 2、TDictionary另一个限制:它不保留元素添加的顺序 | |
Add | O(1) | O(n) | O(n)只会发生特别定制的数据集上,在实际应用中是不容易遇到的。 | |
Remove | O(1) | O(n) | O(n)只会发生特别定制的数据集上,在实际应用中是不容易遇到的。 | |
TryGetValue | O(1) | O(n) | 1、性能优异。O(n)只会发生特别定制的数据集上,在实际应用中是不容易遇到的。 2、TDictionary 总是存储【对】的键和值。如果因为没有与任何特定键相关联的值数据,只需要键的话(Delphi 不允许我们忽略值部分),我们可以因此将代码将值定义为布尔值,并始终将其设置为True。 | |
ContainsKey | O(1) | O(n) | 性能优异。O(n)只会发生特别定制的数据集上,在实际应用中是不容易遇到的。 | |
ContainsValue | O(1) | 性能优异 | ||
小结 | O(n)算法(比如本例的未排序列表)的运行速度比 O(log n)算法(比如本例的排序列表)慢得多,而O(1)算法(比如本例的TDictionary字典)是上述算法中最快的。 |
procedure TfrmRandomWordSearch.LoadWords(wordList: TStringList);
var
word: string;
begin
//:将英语单词数据库中的所有单词加载到内部数据结构中。
//资料来源:https://github.com/dwyl/english-words。
//数据库版权所有:infochimps
FWordsUnsorted := TStringList.Create;
FWordsUnsorted.Assign(wordList);
//:未排序列表:您将看到,生成一个新单词通常需要几百毫秒到几秒钟。
//:由于进程是随机的,并且依赖于 CPU 速度
FWordsSorted := TStringList.Create;
FWordsSorted.Assign(wordList);
FWordsSorted.Sorted := True;
//:排序列表:单词将计算得比“未排序列表”快得多。
FWordsDictionary
:= TDictionary<string,boolean>.Create(wordList.Count);
for word in wordList do
FWordsDictionary.Add(word, True);
//:而TDictionary方法在100毫秒内就能找到一个新词,
//:它比“排序列表”和“未排序列表”快得多。
end;
procedure TfrmRandomWordSearch.FindGoodWord(
const wordTest: TWordCheckDelegate);
var
word: string;
isWordOK: boolean;
time: TStopwatch;
begin
time := TStopwatch.StartNew;
repeat
word := GenerateWord;
isWordOK := wordTest(word);
until isWordOK or (time.ElapsedMilliseconds > 10000);
//:随机提取不同长度的单词(10秒即为超时)
if isWordOK then
lbWords.ItemIndex
:= lbWords.Items.Add(
Format('%s (%d ms)',
[word, time.ElapsedMilliseconds] )
)
else
lbWords.ItemIndex := lbWords.Items.Add('timeout');
end;
虽然算法及其时间复杂度是有用的,但它不会在任何场合都有帮助。有时你已经使用了最好的算法,但你的程序仍然太慢。在这种情况下,您应找到程序的慢部分,并使用任何可能的技巧去加速它们。要做到这一点,你必须先找到它们。比如:慢,满是慢在哪里了,是慢在Add,还是慢在Sort,等等。