2013-04-30 47 views
1

德尔福的版本时: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,重建指针列表并重新排序。

现在,我没有大量的单元,所以没有性能问题。然而,当我删除一个单元格并重新排列指针时,重新编译指针全部指针每次数组更改对我来说似乎都是错误的。如果我的问题看起来很愚蠢,我很抱歉,但我正在努力学习。

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

+0

是的,你应该在插入排序的位置,而不是每次添加后进行昂贵的排序算法的新元素。 – OnTheFly 2013-04-30 19:22:15

+0

实现一个链接列表,而不是使用Array或TList – 2013-04-30 19:35:40

+0

@Tony这是一个简单的插入数据结构。放弃随机访问是疯狂的这种情况。 – 2013-04-30 19:41:34

回答

7

有两种方法来处理,这取决于使用情况。但首先,您应该使用TList而不是数组。它具有处理插入和删除以及保持顺序的方法。

如果你在一个时间进行大量插入,你会想用脏插入算法,它是这样工作的:

列表带有相关的标志,一个布尔值称为 Dirty。插入内容时,请将其粘贴在列表的最后, 并将Dirty设置为True。当您从列表中读取时,首先检查Dirty标志,如果其值为True,则对列表进行排序,设置 Dirty := False;然后执行读取操作。有了大量的插入,这个 比插入时按排序顺序保存列表要快得多。

但是,如果您不可能一次执行多个插入操作,按排序顺序维护列表会更便宜。不过,您无需每次都拨打Sort来完成此操作。你不喜欢这样:

因为您的数据已经排序,你可以通过使用binary search找到一个新的价值的正确位置 。使用插入 操作使用二分查找来确定新值应该在哪里去,将其插入那里,并且您的列表保持按排序顺序。

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

+0

+1这是比我的更好的答案 – 2013-04-30 20:06:01

+0

嗯我知道算法,(脏插入)从来不知道它有一个正式的名字,虽然 – 2013-04-30 20:18:45

+0

@托尼:我不知道这是否是一个正式的名称,这正是我所说的:P – 2013-04-30 21:26:21

0

同时使用动态数组和TList不是好。使用一个或其他,但不是两个。在TList中插入很容易,但是您需要管理指针的生命周期。您正在查看堆分配。对于动态数组,寿命很简单,但插入和删除需要小心。当然,如果你有现代德尔福,那么TList就是微不足道的。

使用插入排序来维护数组的排序。每当插入一个新项目时,将它插入到一个大于前一个元素的位置,并且小于后面的元素。如果您的列表已经订购了,那么在此规则后插入维护订购的属性。为了提高效率,您可以使用二分查找来查找插入点。有关Sorted为True时的TStringList示例。

在解决二进制搜索问题之前(令人惊讶地难以理解),请使用线性搜索来实现一个版本。向你自己证明这个工作,然后继续进行二分查找,如果你需要额外的效率。

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

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

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

鉴于它是唯一的名称和价格,你可以作弊和使用TStringList完成整个事情,或者更好的还是一个隐藏它的类 – 2013-04-30 19:44:14

+0

谢谢你们的帮助,我会看看TStringList的例子。 :我删除了指针yes,但是我也删除了单元本身,并重建了数组索引(例如,如果我删除单元格4,单元格6变成单元格5 ...) – 2013-04-30 19:52:05

+0

@AllainMcCain。基本上是因为你是使用数组如果你切换到某种列表(没有双关语意),它会为你做那个。 – 2013-04-30 20:15:28

0

那么,如果你想维护一个有序名称列表及其数据,则使用TStringList而不是TList。 使用其对象属性保留记录引用。

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

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; 
+0

啤酒花,托尼霍普金森已经建议使用TStringList中。我没看见它。下次我应该仔细阅读所有的评论。 – 2013-05-01 20:17:28

相关问题