使用的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;
现在,我希望能够在保持指针排序的同时添加和删除单元格。现在,这是我的问题。
SortedInfo.Sort(@CompareInfo);
来获取整个指针列表现在,我没有大量的单元,所以没有性能问题。但是,当我删除一个单元格并在每次更改数组时对 all 指针进行排序时重建指针对我来说似乎是错误的。如果我的问题看起来很愚蠢,我很抱歉,但我正在努力学习。
有没有正确的方法来保持我的数组排序?我不确定我应该如何“单独”对新单元格进行排序,或者在删除单元格时我应该如何保持指针有效...
答案 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;