我想在一个大的(50mb +)字节数组中搜索一个int。我应该使用什么算法?也许是一些不安全的方法?
编辑: 它不是一个int数组,它是一个字节数组。数据没有以任何方式排序。
答案 0 :(得分:3)
public IList<int> FindIntInBytes(byte[] bytes, int target)
{
IList<int> found = new List<int>();
unsafe
{
fixed (byte* pBytes = bytes)
{
byte* pCurrent = pBytes;
for (int i = 0; i <= bytes.Length - 4; i++, pCurrent++)
{
if (target == *(int*)pCurrent)
{
found.Add(i);
}
}
}
}
return found;
}
不适用于大端架构,但它们并不适用于大多数.Net应用程序。
分成几个部分并在多个线程中运行,然后合并结果以获得更快的性能,具体取决于阵列的大小和CPU可用性。
答案 1 :(得分:2)
这是我的实施。在O(n)中工作;
int findInArray(byte[] array, int what)
{
byte[] toMatch = /* convert your dword to a 4 elements byte array */;
int matched = 0;
for(int i = 0; i < array.length; i++) {
if(array[i] == toMatch[matched]) {
matched += 1;
if(matched == 4) {
return i - 4;
}
}
else {
i -= matched;
matched = 0;
}
}
return -1;
}
答案 2 :(得分:1)
您实际上在做的是在字符串中查找子字符串。因此,您需要查看string search algorithms。
BlackBear建议是一个天真的字符串搜索。你也可以使用,例如, Knuth–Morris–Pratt algorithm
答案 3 :(得分:1)
这听起来像是一个你可能想要从数组中提取整数并设置一个简单的哈希表或二叉树的工作,如果你在相同的数据上做了很多搜索。出于同样的原因,数据库具有索引。您可以获得N / 2或更好的性能,具体取决于您的索引。
请参阅此文章:How does database indexing work?
这篇文章:http://en.wikipedia.org/wiki/Binary_tree
如果您想要走这条路线,请打开一个新问题,了解哪一个更适合您正在处理的任务。
答案 4 :(得分:1)
从算法上讲,搜索整个事物没有捷径可走。实现方面,如果性能成为一个大问题,那么您可以做的最好就是编写代码以尽可能避免内存读取,分支和函数调用。这将使编译器更容易生成有效的代码(尽管聪明的编译器可能无论如何,当您编译到VM然后将其重新编译为运行的机器代码时,很难保证任何关于最终机器代码的信息)。我的实现看起来像这样:
System.Collections.Generic.IEnumerable<int> FindIntInByteArray(int match, byte[] array) {
if (array.Length < 4) yield break;
byte b0 = 0;
byte b1 = array[0];
byte b2 = array[1];
byte b3 = array[2];
int len = array.Length;
for (int i=3;i<len;i++) {
b0 = b1;
b1 = b2;
b2 = b3;
b3 = array[i];
/* The following line should be changed depending on endian-ness or which
bytes are to be considered most significant. */
int comp = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
if (comp == match) yield return i-3;
}
}
答案 5 :(得分:0)
即使在.Net 2.0中,您也可以创建新的线程,以便您可以并行搜索它。你没有提到你是否正在寻找int的所有实例。我可以想到几种提高速度的方法而不是直接搜索,包括将数组预处理成字典以进行查找等,如果你总是使用相同的数组来查找数据等。
答案 6 :(得分:0)
这是一种方法。它只需要查看每个第4个字节,因此应该稍快一些。 (如果你正在寻找0x11223344,并且你找到一个0x55,你知道目标整数根本不包含这个字节。)应该是O(n / 4)。
我没有运行此操作,可能存在语法或逐个错误。
bool Compare4(byte[] searchIn, int offset, byte[] searchFor)
{
return searchIn[offset] == searchFor[0] &&
searchIn[offset+1] == searchFor[1] &&
searchIn[offset+2] == searchFor[2] &&
searchIn[offset+3] == searchFor[3];
}
/// Returns index if found, -1 if not found.
int FindIntInArray(int target, byte[] array)
{
byte[] targetArray = new byte[4];
targetArray[0] = target & 0xFF;
targetArray[1] = (target>>8) & 0xFF;
targetArray[2] = (target>>16) & 0xFF;
targetArray[3] = (target>>24) & 0xFF;
bool[] bytesUsed = new bool[256];
foreach(byte b in targetArray) bytesUsed[b] = true;
for(int i = 3; i < array.Length - 3; i += 4)
{
if(bytesUsed[array[i]])
{
if(Compare4(array, i-3, targetArray)) return i-3;
if(Compare4(array, i-2, targetArray)) return i-2;
if(Compare4(array, i-1, targetArray)) return i-1;
if(Compare4(array, i, targetArray)) return i;
}
}
return -1;
}
答案 7 :(得分:0)
如果我理解你的问题,你想在一个字节数组中搜索4个字节的特定模式。以下应该可以做到这一点,在数组中的任意位置处找到int值 - 没有关于对齐的假设。
编辑注意
以下是代码:
private static int FindIntValueInByteArray( int value , byte[] octets )
{
int matchPosition = -1 ; // assume no match
for ( int i = 0 ; i < octets.Length-3 ; ++i )
{
int t = BitConverter.ToInt32( octets , i ) ;
if ( t == value )
{
matchPosition = i ;
break ;
}
}
return matchPosition ;
}
答案 8 :(得分:0)
public static class ByteListExtensions
{
public static IEnumerable<int> AllIndexesOf(this IList<byte> source, int match, bool isLittleEndian = true)
{
if (source.Count < 4)
{
return Enumerable.Empty<int>();
}
var b0 = (byte)(match & (isLittleEndian ? 0xff000000 : 0x000000ff));
var b1 = (byte)(match & (isLittleEndian ? 0x00ff0000 : 0x0000ff00));
var b2 = (byte)(match & (isLittleEndian ? 0x0000ff00 : 0x00ff0000));
var b3 = (byte)(match & (isLittleEndian ? 0x000000ff : 0xff000000));
var indexes = Enumerable.Range(0, source.Count / 4)
.AsParallel()
.Select(x => x * 4)
.Where(x => source[x] == b0)
.Where(x => source[x + 1] == b1)
.Where(x => source[x + 2] == b2)
.Where(x => source[x + 3] == b3);
return indexes;
}
}
样本用法:
var callingAssembly = Assembly.GetCallingAssembly();
var bytes = File.ReadAllBytes(callingAssembly.Location);
const int intToFind = 42;
var indexes = bytes.AllIndexesOf(intToFind);
foreach (var index in indexes)
{
Console.WriteLine(index);
}