添加/删除单元格时保持数组排序的最佳方法

时间:2013-04-30 19:17:20

标签: arrays delphi sorting record tlist

使用的Delphi版本:2007

您好,

我有一个Tecord数组

TInfo = Record
 Name : String;
 Price : Integer;
end;

var Infos : Array of Tinfo;

我一直在寻找一种方法来对我的Infos数组进行排序,并找到了我认为聪明的方法。基本上,我有一个TList,我在其中添加指向数组的每个单元格的指针;然后,我使用自定义排序功能对它们进行排序。然后,此TList用于显示TListView中已排序的单元格,OwnerData设置为true

var SortedInfo : TList;

...

function CompareInfo(Item1, Item2: Integer): Integer;
var
 i, j : integer;
begin
 i := Integer(Item1);
 j := Integer(Item2);
 Result := CompareText(Infos[i].Name, Infos[j].Name);
end;

...

for I := 0 to Length(Infos) - 1 do SortedInfo.Add(Pointer(I));
SortedInfo.Sort(@CompareInfo);

...

procedure InfoHandlerData(Sender: TObject; Item: TListItem);
begin
 Item.Caption := Infos[Integer(SortedInfo[Item.Index])].Name;
 Item.SubItems.Add(IntToStr(Infos[Integer(SortedInfo[Item.Index])].Price);
end;

现在,我希望能够在保持指针排序的同时添加和删除单元格。现在,这是我的问题。

  1. 当我添加一个单元格时,我必须通过调用SortedInfo.Sort(@CompareInfo);来获取整个指针列表
  2. 删除单元格时,我必须清理TList,重建指针列表并重新排序。
  3. 现在,我没有大量的单元,所以没有性能问题。但是,当我删除一个单元格并在每次更改数组时对 all 指针进行排序时重建指针对我来说似乎是错误的。如果我的问题看起来很愚蠢,我很抱歉,但我正在努力学习。

    有没有正确的方法来保持我的数组排序?我不确定我应该如何“单独”对新单元格进行排序,或者在删除单元格时我应该如何保持指针有效...

3 个答案:

答案 0 :(得分:7)

根据使用情况,有两种方法可以解决这个问题。但首先,您应该使用TList而不是数组。它有处理插入和删除以及保持秩序的方法。

如果您一次执行大量插入操作,则需要使用脏插入算法,其工作方式如下:

  

该列表附带一个关联的标志,一个名为的布尔值   Dirty。插入内容时,将其粘贴在列表的末尾,   并将Dirty设置为True。当你从列表中读取时,首先   检查Dirty标志,如果其值为True,则对列表进行排序,设置   Dirty := False;,然后阅读。有很多插入,这个   比插入时保持列表排序顺序要快得多。

但是,如果您不可能一次进行多次插入,则按排序顺序维护列表会更便宜。不过,每次调用Sort都不需要这样做。你这样做:

  

由于您的数据已经排序,因此您可以找到正确的位置   使用binary search获取新值。有插入   操作使用二进制搜索来确定新值的位置   去,把它插入那里,你的清单按排序顺序排列。

至于删除,您不必担心排序顺序。只需在Delete上拨打TList,如果它开始排序,则删除项目不会改变该项目。

答案 1 :(得分:0)

同时使用动态数组和TList并不好。使用一个或另一个,但不是两个。在TList中插入很容易,但是您需要管理指针的生命周期。你正在看堆分配。对于动态数组,生命周期很容易,但插入和删除需要一点小心。当然,如果你有现代的Delphi,那对TList来说是微不足道的。

使用插入排序来维护数组的顺序。无论何时插入新项目,请将其插入大于前一个元素的位置,并小于后续元素。如果您的列表已经订购,则按照此规则插入会保留已订购的属性。为了提高效率,您可以使用二进制搜索来查找插入点。有关在Sorted为True时查看TStringList的示例。

在你处理二进制搜索之前(令人惊讶的是要做对了),实现一个带线性搜索的版本。向自己证明这是有效的,然后如果你需要额外的效率,继续二进制搜索。

删除时,只需删除该项目即可。从有序数组中删除任何项目都会保留有序的属性。

您的比较功能有点“奇怪”。您所需要的只是:

function CompareInfo(Item1, Item2: Integer): Integer;
begin
  Result := CompareText(Infos[Item1].Name, Infos[Item2].Name);
end;

答案 2 :(得分:0)

好吧,如果你想维护一个有序名称列表及其数据,请使用TStringList而不是TList。 使用其Objects属性来保留记录引用。

无论是插入还是删除项目,它都会为您排序。 例如:

Var
   List:TStringList;
begin
   List:=TStringList.Create();
   List.Sorted:=True;
   // depending on your duplicates records use one of the following:
   List.Duplicates:=[dupIgnore, dupAccept, dupError];

   // You add record to the list this way:
   List.AddObject(RecPtr^.name, TObject(RecPtr));
   // or
   List.AddObject(MyRecord.name, TObject(@MyRecord));
   // When you want to access the record from an item, typecast it
   with TMyRecordType(List.Objects[IndexToTheObject])^ do
   begin
   end;

   // To delete an item:
   List.Delete(Index);

   // To find a specific record:
   Index:=List.IndexOf(MyNameSearch);
end;