TList和BinarySearch错误

时间:2011-11-27 17:18:39

标签: delphi delphi-xe2

我在TList和BinarySearch方面遇到了一些问题。我有这个结构:

  PDoubleEstr = record
    Double: array [1..2] of Integer;
    Count: Integer;
  end;
  TDoubleEstr = TList<PDoubleEstr>;

并声明:

var oDoubleEstr: TDoubleEstr;

然后,我使用此函数正确初始化列表:

procedure Initialize;
var
  iIndex1, iIndex2: Integer;
  rDoubleEstr: PDoubleEstr;
begin
  oDoubleEstr.Clear;
  for iIndex1 := 1 to 89 do
    for iIndex2 := Succ(iIndex1) to 90 do
    begin
      with rDoubleEstr do
      begin
        Double[1] := iIndex1;
        Double[2] := iIndex2;
        Count := 0;
      end;
      oDoubleEstr.Add(rDoubleEstr);
    end;
end;

现在,我定义了这个程序:

procedure Element(const First: Integer; const Second: Integer; var Value: PDoubleEstr);
begin
  with Value do
  begin
    Double[1] := First;
    Double[2] := Second;
  end; 
end;

然后在我的主要程序中:

procedure Main;
var 
  Value: PDoubleEstr;
  Index: Integer;
  flag: boolean;
begin
  Element(89, 90, Value);
  flag := oDoubleEstr.BinarySearch(Value, Index, TDelegatedComparer<PDoubleEstr>.Construct(Compare));
  Writeln(Flag:5, oDoubleEstr[Index].Double[1]:5, oDoubleEstr[Index].Double[2]:5);  
end;

这让我感到错误。从某种意义上说索引“索引”的元素与我输入的元素不对应。 当然,oDoubleEstr正确排序,不明白我错在哪里。 构造比较如此定义:

function TDouble.Compare(const Left, Right: PDoubleEstr): Integer;
begin
  Result := Sign(Left.Double[1] - Right.Double[2]);
end;

我认为错误在构造中,但不理解为解决它。 一般来说,我想检查元素是否存在,如果存在则获取索引。作为元素我的意思是在我的情况下只有字段Double。 我试着更好地解释一下,我的名单如此填充:

 1   2    // element 0
 1   3    
......
 1  90    
......
88  89
88  90
89  90    // element 4004

如果我将Element设置为(89,90),它应该将我作为索引值:4004,如果找到则为true,否则为false。 谢谢你的帮助。

2 个答案:

答案 0 :(得分:2)

我不确定你要做什么,但Compare函数无效。 Compare函数需要具有以下对称属性:

Compare(a, b) = -Compare(b, a)

您的功能没有此属性,因为您将Double[1]Double[2]进行了比较。

您还可以通过比较功能中的减法运行范围错误的风险。我会改用<>运算符。

我不愿意建议比较功能应该是什么,因为我不确定你想要的订购标准是什么。如果您想要词典比较(即按字母顺序排序),则首先比较Double[1]值,如果它们相等,则执行Double[2]值的第二次比较。

但是,现在我再次查看了构建列表的方式,现在我看到你断言这个列表是按构造排序的,很清楚订单函数应该是什么。像这样:

function CompareInt(const Left, Right: Integer): Integer;
begin
  if Left<Right then begin
    Result := -1
  else if Left>Right then
    Result := 1
  else
    Result := 0;
end;

function Compare(const Left, Right: PDoubleEstr): Integer;
begin
  Result := CompareInt(Left.Double[1], Right.Double[1]);
  if Result=0 then
    Result := CompareInt(Left.Double[2], Right.Double[2]);
end;

请注意,我已将原始版本(尽管有缺陷的版本)的比较功能的符号反转。您的次要问题(请参阅对Ville的回答的评论)是因为列表没有按照您用于搜索的顺序排序。您必须使用相同的比较进行排序和搜索。二元搜索算法就是基于此。


顺便说一下,我认为Double是一个糟糕的变量名,因为它也是一种基本类型。使用PDoubleEstr命名记录非常令人困惑,因为P前缀的常规用法是指针。

答案 1 :(得分:1)

是David Hefferman是对的。如果您像这样定义比较函数,它将起作用:

function Compare(const Left, Right: PDoubleEstr): Integer;
begin
  Result := Sign(Left.Double[1] - Right.Double[1]);
  if Result=0 then
    Result := Sign(Left.Double[2] - Right.Double[2]);
end;

重要的是你需要比较double数组中的两个值才能得到匹配。