在Delphi中调整动态数组大小的最佳方法是什么?

在Delphi中调整动态数组大小的最佳方法是什么?,delphi,Delphi,作为一名Delphi新手,我编写了一个简单的函数,该函数给定一个字符串和一个字符,返回该字符在字符串中出现的索引 但是,我不确定我的实现是否最优(因为我一直在调整动态数组的大小)。有没有更好的方法来实现这一点: type Indexes = array of Integer; function GetCharacterIndexesInString(inputstring:string; c:char) : Indexes; var s : char; count : intege

作为一名Delphi新手,我编写了一个简单的函数,该函数给定一个字符串和一个字符,返回该字符在字符串中出现的索引

但是,我不确定我的实现是否最优(因为我一直在调整动态数组的大小)。有没有更好的方法来实现这一点:

type Indexes = array of Integer;

function GetCharacterIndexesInString(inputstring:string; c:char) : Indexes;
  var
  s : char;
  count : integer;
  position: integer;

  begin
    count := 0;
    position := 0;
    SetLength(result, 0);
    for  s in inputstring do
    begin
      if s = c then
      begin
        count := count+1;
        SetLength(result, count);
        result[count-1] := position;
      end;
      position := position+1;
    end;
  end;

当最终大小未知时,有一种经典的渐进快速调整阵列大小的算法。我们不是将其大小调整1,而是在空间不足时将其大小加倍。完成后,设置数组的实际大小

代码如下:

type Indexes = array of Integer;

function GetCharacterIndexesInString(inputstring:string; c:char) : Indexes;
  var
  s : char;
  count : integer;
  position: integer;
  capacity: Integer; //TList uses same method internally :)

  const InitCapacity: Integer = 16;
  begin
    count := 0;
    position := 0;
    capacity := InitCapacity;
    SetLength(result, InitCapacity);
    for  s in inputstring do
    begin
      if s = c then
      begin
        inc(count); //adds 1 to count, delphi analog of ++
        if count > capacity then begin
          capacity := capacity * 2;
          SetLength(result, capacity);
        end;
        result[count-1] := position;
      end;
      inc(position);
    end;
    SetLength(result, count);
  end;

UPD。根据David Heffernan的建议修改了代码,现在它以16的长度开始,这应该会加快一点速度。此外,还可以“调优”InitCapacity,代码在这里使用任何正数。例如,您可以收集统计信息:结果数组的平均长度,并将InitCapacity设置为略大于此平均长度。

可能取决于您提供的典型输入。我怀疑一种算法对于所有可能的输入都是最优的。另一种方法是使用TList而不是动态数组。在那里,它已经实现了,我们不关心长度,而不是'result[count-1]:=position'write'result.Add(position)'。但有一个警告:这个函数的结果必须在某个时候释放。这在早期分配中可能是浪费的,因为会有一个最小的块大小。我可能从16或32开始,或者更好。首先读入固定长度数组。如果它已满,请切换到动态数组。如果没有,您可以通过一个堆分配完成整个任务。FWIW,有人抱怨
TList
,当必须调整数组大小时,它确实会使数组大小加倍。人们更喜欢
TList
(非通用)的功能,即只添加当前大小的一半。他们发现加倍太浪费了。很可能,
TList
实际上更浪费,执行更多的分配,并创建无法重复使用的块。例如,您可能会得到大小为256、384和512的块,而不仅仅是256和512的块。如果这1.5倍的数据块可以重复使用,那么
TList
方法的浪费就更少了。大多数人在讨论这些问题时,对内存分配在各个级别(系统和库)的工作原理了解不够,无法构造有效的参数。@DavidHeffernan I更新了答案,从数组大小16开始。