如果我有一系列项目:
1, 2, 3, 4, 5, 6, 7, 8
我想选择一系列项目并将它们移动到数组中的另一个位置。例如:
1, 2, 5, 6, 7, 3, 4, 8
此处,5,6,7段已移至指数2。
最有效的方法是什么,特别是限制额外阵列副本的数量。我有一个版本工作,但它效率低,并且在我的算法中形成了一个核心角色,我正在尝试优化。
感谢。
答案 0 :(得分:3)
尝试使用链接列表。由于您正在移动列表的子部分,因此在子列表的任一端移动引用比在同一子列表中复制每个单独的项目更具内存效率。总的时间复杂度是相同的(Θ(n)遍历链表,Θ(n)复制数组段),但你会有更好的内存复杂性(常数n而不是Θ(n))和连续内存分配/释放的问题较少。
答案 1 :(得分:2)
一种方法是切出应该移动的项目,然后移动现有成员:
// T[] source
// int dest
// int start, end
T[] slice = new T[end - start];
Array.Copy(source, start, slice, 0, slice.Length);
if (dest < start)
{
// push towards end
Array.Copy(source, dest, source, dest + slice.Length, start - dest);
}
else
{
// push towards start
// who moves where? Assumes dest..dest+count goes left
Array.Copy(source, end, source, dest, dest - start);
}
Array.Copy(slice, 0, source, dest, slice.Length);
答案 2 :(得分:1)
我知道你选择了一个答案;但这个问题真的在我的眼前;看看是否可以用另一种方式写出来。
所以我想出了这段代码:
static int[] MoveSlice(int[] arr, int startIndex, int length, int newIndex)
{
var delta = (int)Math.Abs(newIndex - startIndex);
if (delta >= length)
{
for (var i = 0; i < length; i++)
{
var swap = arr[startIndex + i];
arr[startIndex + i] = arr[newIndex + i];
arr[newIndex + i] = swap;
}
}
else
{
var newStart = newIndex + length;
for (var i = 0; i < delta; i++)
{
var swap = arr[newStart + i];
arr[newStart + i] = arr[newIndex + i];
arr[newIndex + i] = swap;
}
var l = (int)Math.Abs(length - delta);
arr = MoveSlice(arr, newIndex + delta, l, newIndex);
}
return arr;
}
我还没有测试性能。但我很乐意解决它!
也许您需要使用更多代码来检查边界等可能出现的错误。
答案 3 :(得分:0)
如果你想避免为了效率而制作数组副本,你可以完全避免它们。您可以将单个值的最小变量用于将项目移动到新目标。这样的算法在内存上非常有效,并且整体上也很有效,尽管它显然无法利用原生,高效的数组复制。