在算法理论中,众所周知,优化速度会消耗内存,反之亦然。我的算法使用更多的内存(不多),但作为回报只扫描一次大数组。
public static int GetOffsetOfArrayInArray(byte[] bigArray, int bigArrayOffset, int bigArrayCount, byte[] smallArray)
{
// TODO: Check whether none of the variables are null or out of range.
if (smallArray.Length == 0)
return 0;
List<int> starts = new List<int>(); // Limited number of elements.
int offset = bigArrayOffset;
// A single pass through the big array.
while (offset < bigArrayOffset + bigArrayCount)
{
for (int i = 0; i < starts.Count; i++)
{
if (bigArray[offset] != smallArray[offset - starts[i]])
{
// Remove starts[i] from the list.
starts.RemoveAt(i);
i--;
}
else if (offset - starts[i] == smallArray.Length - 1)
{
// Found a match.
return starts[i];
}
}
if (bigArray[offset] == smallArray[0] &&
offset <= (bigArrayOffset + bigArrayCount - smallArray.Length))
{
if (smallArray.Length > 1)
// Add the start to the list.
starts.Add(offset);
else
// Found a match.
return offset;
}
offset++;
}
return -1;
}
该列表starts
用于跟踪 in 的潜在起始偏移smallArray
量bigArray
。smallArray[0]
它永远不会包含比in出现次数更多的元素smallArray
(可以提前计算以优化列表并减少内存重新分配的次数)。当没有足够的字节bigArray
包含smallArray
时,不会尝试,当smallArray
找到时,算法停止。当到达结束时它也会停止bigArray
。因此,最坏情况下的运行时间为 O(1),内存使用量为 O(1)。
进一步可能的优化包括在不安全的代码中使用指针,并用可以预先计算大小的固定数组替换列表(如前所述)。但是,因为在列表中删除了错误的偏移量(较小的内循环)并且在数组中必须跳过错误的偏移量(固定大小的内循环但可能更快的元素访问),您必须对哪个更快进行基准测试。
您是否期望smallArray
变大也很重要。当你这样做时,你可以在 while 循环中添加一个检查来检查starts.Length != 0 || offset <= (bigArrayOffset + bigArrayCount - smallArray.Length)
. 否则循环可能会停止并且没有发现任何事件。