我在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。 谢谢你的帮助。
答案 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数组中的两个值才能得到匹配。