我需要在N个位置向右和向左移动一个数组。
我转移到的那一侧弹出的物品必须回到另一侧。
向右移动13:
[0,1,2,3,4,5,6,7,8,9] -> [7,8,9,0,1,2,3,4,5,6]
左转15:
[0,1,2,3,4,5,6,7,8,9] -> [5,6,7,8,9,0,1,2,3,4]
此操作将发生数百万次,并且必须非常快。
我目前的实施如下。请查看并建议是否需要进行一些优化。
if (shift > 0)
{
int offset = array.Length % shift;
if (offset > 0)
{
byte[] temp = new byte[offset];
if (!right)
{
Array.Copy(array, temp, offset);
Array.Copy(array, offset, array, 0, array.Length - offset);
Array.Copy(temp, 0, array, array.Length - offset, temp.Length);
}
else
{
Array.Copy(array, array.Length - offset, temp, 0, offset);
Array.Copy(array, 0, array, offset, array.Length - offset);
Array.Copy(temp, 0, array, 0, temp.Length);
}
}
}
作为关于它将被转移多少的提示(但我怀疑它可以导致优化):
- depends on the entropy of the array itself
- for aray that are full of same values it will get shifted roughtly 0
- more entropy means higher shift value
- direction of shift will be used generally more to the left
PS。无法获得运行不安全代码的安全权限:/
PS2:结果数组必须作为数组向前传递到不同的库以进行进一步处理,所以我不能只是换行和重新索引。
PS3:我更喜欢在同一个数组上工作,因为该方法使用ref
,并且在新数组上执行此操作然后复制将非常耗时(我正在使用'temp'数组对于因转移而失败的部分。
答案 0 :(得分:13)
您应该使用Buffer.BlockCopy
代替。它绕过数组索引并执行快速内存复制。请注意,BlockCopy
以字节为单位复制数据,而不是根据数组元素的大小进行复制,因此请务必使用sizeof()
来解释数据。
答案 1 :(得分:4)
只需保存数组第一个元素的索引即可。当您需要在移位数组中获取值时,只需将其添加到迭代索引中即可 当您需要进行移位时,将移位值添加到第一个元素的索引。
答案 2 :(得分:4)
如果你真的需要创建一个新的移位数组,请使用Buffer.BlockCopy()
(我假设示例中有一个int数组,同样适用于任何其他类型):
int [] sourceArray = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int [] targetArray = new int[sourceArray.Length];
int shift = 13;
int offset = shift % sourceArray.Length;
Buffer.BlockCopy(sourceArray, offset*sizeof(int), targetArray, 0 , (sourceArray.Length - offset)*sizeof(int));
Buffer.BlockCopy(sourceArray, 0, targetArray, (sourceArray.Length - offset) * sizeof(int), offset * sizeof(int));
答案 3 :(得分:2)
根本不要复制。创建轻量级对象,用于存储对数组的引用和移位值。然后在需要检索值时使用这些对象。
如果你需要在同一个数组上“堆叠”几个班次,优化我只创建一个图层的情况(添加传入对象的移位)。
答案 4 :(得分:2)
internal static void ShiftCircular(int offset, object[] array)
{
if (offset == 0 || array.Length <= 1)
return;
offset = offset % array.Length;
if (offset == 0)
return;
if (offset < 0)
offset = array.Length + offset;
Array.Reverse(array, 0, array.Length);
Array.Reverse(array, 0, offset);
Array.Reverse(array, offset, array.Length - offset);
}
它支持圆形左移和右移,仅适用于给定的数组。
答案 5 :(得分:0)
如果你不能使用模数
的圆形索引,你可以使用这样的东西public byte[] ShiftBytes(byte[] arr, int shift, bool isRight)
{
byte[] newBytes = new byte[arr.Length];
shift = (isRight) ? shift : -1 * shift;
for (int i = 0; i < arr.Length; i++)
newBytes[i] = arr[(((i + shift) % arr.Length)
+ arr.Length) % arr.Length];
return newBytes;
}