列出交叉点

时间:2011-05-23 16:09:53

标签: delphi list intersection

我想计算一个列表“十字路口”。问题是:

L1 = [1, 0, 2, 3, 1 , 3, 0, 5]
L2 = [3, 5]

然后结果将是

L3 = [0, 0, 0, 1, 0, 1, 0, 1]

然后我将在一个字节中转换此结果。在这种情况下,将以十进制格式为21。

我想在delphi中制作,我需要这样做有效。有没有办法比O(m * n)更好地解决这个问题?

3 个答案:

答案 0 :(得分:3)

这是一个应该做你想要的功能。我将L2定义为集合而不是数组,因为您说所有值都适合Byte。它的复杂性是O(n);检查集成员资格在恒定时间内运行。但由于结果需要适合一个字节,L1的长度必须绑定为8,因此该函数的复杂度实际上是O(1)。

function ArrayMembersInSet(const L1: array of Byte; const L2: set of Byte): Byte;
var
  i: Integer;
  b: Byte;
begin
  Assert(Length(L1) <= 8,
    'List is to long to fit in result');
  Result := 0;
  for i := 0 to High(L1) do begin
    b := L1[i];
    if b in L2 then
      Result := Result or (1 shl (7 - i));
  end;
end;

答案 1 :(得分:1)

Rob的回答将适用于这个具体案例。对于需要比较两个列表的更一般情况,如果两个列表都已排序,则可以在O(m + n)时间内完成。 (或者如果你必须先对它们进行排序,则为O(n log n)时间,但这仍然比O(m * n)快很多。)

基本列表比较算法如下所示:

procedure ListCompare(list1, list2: TWhateverList; [Add extra params here]);
var
  i, j: integer;
begin
  i := 0;
  j := 0;
  while (i < list1.Count) and (j < list2.Count) do
  begin
    if list1[i] < list2[j] then
    begin
      //handle this appropriately
      inc(i);
    end
    else if list1[i] > list2[j] then
    begin
      //handle this appropriately
      inc(j);
    end
    else //both elements are equal
    begin
      //handle this appropriately
      inc(i);
      inc(j);
    end;
  end;

  //optional cleanup, if needed:
  while (i < list1.Count) do
  begin
    //handle this appropriately
    inc(i);
  end;
  while (j < list2.Count) do
  begin
    //handle this appropriately
    inc(j);
  end;
end;

这可以针对一大堆任务进行自定义,包括列表交集,通过更改“适当处理”这些位置,并且保证不会运行比两个列表放在一起的更多步骤。对于列表交集,使用等于大小写将值添加到某个输出,而另外两个除了推进计数器之外什么也不做,您可以不进行可选的清理。

使用这种算法的一种方法是将顶部的额外参数设置为函数指针,并传入将处理适当情况的例程,或者不执行任何操作。 (如果你走这条路,请确保在调用它们之前检查nil!)这样你只需要编写一次基本代码。

答案 2 :(得分:0)

无论您需要访问每个列表中的每个元素,比较值。嵌套循环可以在O(n ^ 2)中完成此操作,转换应该只是本地工作。

编辑:我注意到你想要比O(n * m)更好的运行时间。