gpt4 book ai didi

c# - 两个排序整数数组的快速交集

转载 作者:可可西里 更新时间:2023-11-01 08:43:04 25 4
gpt4 key购买 nike

我需要找到两个已排序整数数组的交集,而且速度非常快。

现在,我正在使用以下代码:

int i = 0, j = 0;

while (i < arr1.Count && j < arr2.Count)
{
if (arr1[i] < arr2[j])
{
i++;
}
else
{
if (arr2[j] < arr1[i])
{
j++;
}
else
{
intersect.Add(arr2[j]);
j++;
i++;
}
}
}

不幸的是,完成所有工作可能需要数小时。

如何更快地完成?我找到了 this article使用 SIMD 指令的地方。是否可以在 .NET 中使用 SIMD?

你在想什么:

http://docs.go-mono.com/index.aspx?link=N:Mono.Simd单片机

http://netasm.codeplex.com/ NetASM(注入(inject) asm 代码到托管)

还有类似 http://www.atrevido.net/blog/PermaLink.aspx?guid=ac03f447-d487-45a6-8119-dc4fa1e932e1 的东西

编辑:

当我说数千时,我的意思是跟随(在代码​​中)

for(var i=0;i<arrCollection1.Count-1;i++)
{
for(var j=i+1;j<arrCollection2.Count;j++)
{
Intersect(arrCollection1[i],arrCollection2[j])
}
}

最佳答案

更新

The fastest I got was 200ms with arrays size 10mil, with the unsafe version (Last piece of code).

我做过的测试:

var arr1 = new int[10000000];
var arr2 = new int[10000000];

for (var i = 0; i < 10000000; i++)
{
arr1[i] = i;
arr2[i] = i * 2;
}

var sw = Stopwatch.StartNew();

var result = arr1.IntersectSorted(arr2);

sw.Stop();

Console.WriteLine(sw.Elapsed); // 00:00:00.1926156

全文:

我测试了多种方法,发现这个非常好:

public static List<int> IntersectSorted(this int[] source, int[] target)
{
// Set initial capacity to a "full-intersection" size
// This prevents multiple re-allocations
var ints = new List<int>(Math.Min(source.Length, target.Length));

var i = 0;
var j = 0;

while (i < source.Length && j < target.Length)
{
// Compare only once and let compiler optimize the switch-case
switch (source[i].CompareTo(target[j]))
{
case -1:
i++;

// Saves us a JMP instruction
continue;
case 1:
j++;

// Saves us a JMP instruction
continue;
default:
ints.Add(source[i++]);
j++;

// Saves us a JMP instruction
continue;
}
}

// Free unused memory (sets capacity to actual count)
ints.TrimExcess();

return ints;
}

为了进一步改进,您可以删除 ints.TrimExcess();,这也会产生很大的不同,但您应该考虑是否需要该内存。

此外,如果您知道您可能会中断使用交集的循环,并且您不必将结果作为数组/列表,您应该将实现更改为迭代器:

public static IEnumerable<int> IntersectSorted(this int[] source, int[] target)
{
var i = 0;
var j = 0;

while (i < source.Length && j < target.Length)
{
// Compare only once and let compiler optimize the switch-case
switch (source[i].CompareTo(target[j]))
{
case -1:
i++;

// Saves us a JMP instruction
continue;
case 1:
j++;

// Saves us a JMP instruction
continue;
default:
yield return source[i++];
j++;

// Saves us a JMP instruction
continue;
}
}
}

另一个改进是使用不安全代码:

public static unsafe List<int> IntersectSorted(this int[] source, int[] target)
{
var ints = new List<int>(Math.Min(source.Length, target.Length));

fixed (int* ptSrc = source)
{
var maxSrcAdr = ptSrc + source.Length;

fixed (int* ptTar = target)
{
var maxTarAdr = ptTar + target.Length;

var currSrc = ptSrc;
var currTar = ptTar;

while (currSrc < maxSrcAdr && currTar < maxTarAdr)
{
switch ((*currSrc).CompareTo(*currTar))
{
case -1:
currSrc++;
continue;
case 1:
currTar++;
continue;
default:
ints.Add(*currSrc);
currSrc++;
currTar++;
continue;
}
}
}
}

ints.TrimExcess();
return ints;
}

总而言之,最主要的性能影响是在 if-else 中。将它变成一个开关盒产生了巨大的变化(大约快 2 倍)。

关于c# - 两个排序整数数组的快速交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10866756/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com