1

使用的 Delphi 版本:2007

你好,

我有一系列 Tecord

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

var Infos : Array of Tinfo;

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

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,重建指针列表并再次对其进行排序。

现在,我没有大量的单元格,所以没有性能问题。但是,在我删除单元格时重建指针并在每次数组更改时对所有指针进行排序对我来说似乎是错误的。如果我的问题看起来很愚蠢,我很抱歉,但我正在努力学习。

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

4

3 回答 3

8

有两种方法可以处理这个问题,具体取决于使用情况。但首先,您可能应该使用 aTList而不是数组。它具有处理插入和删除以及保持事物有序的方法。

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

该列表带有一个关联标志,一个名为 的布尔值 Dirty。当你插入一些东西时,把它贴在列表的末尾,然后设置DirtyTrue. 当您从列表中读取时,首先检查Dirty标志,如果其值为True,则对列表进行排序,设置 Dirty := False;然后进行读取。对于大量插入,这比在插入时保持列表排序要快得多。

但是,如果您不太可能一次执行多个插入操作,则按排序顺序维护列表会更便宜。不过,您不需要Sort每次都打电话来做到这一点。你这样做:

因为您的数据已经排序,您可以使用二分搜索找到新值的正确位置。让插入操作使用二进制搜索来确定新值应该去哪里,将其插入那里,并且您的列表保持排序顺序。

至于删除,您不必担心排序顺序。只需调用Delete您的TList,如果它开始排序,删除一个项目不会改变它。

于 2013-04-30T19:44:29.777 回答
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;
于 2013-05-01T12:40:52.133 回答
0

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

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

在你处理二分搜索之前(出乎意料地难以正确),实现一个带有线性搜索的版本。向自己证明这是可行的,然后如果您需要额外的效率,则继续进行二进制搜索。

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

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

function CompareInfo(Item1, Item2: Integer): Integer;
begin
  Result := CompareText(Infos[Item1].Name, Infos[Item2].Name);
end;
于 2013-04-30T19:35:08.030 回答