如何通过从头到尾移动 N 个元素来旋转数组?

How to rotate an array by moving N elements from end to start?

我正在尝试使用 C# 将数组中的多个元素移动到末尾。
我有一个数组(在我的例子中是一个字符数组)和一个整数 z。现在我想将 z 个字符移动到另一个数组的末尾,其他字符应该移动到数组的开头。
所以如果第一个数组是{'H','E','L','L','O'}z = 3,新数组应该是{'L','O','H','E','L'}.

我希望有人能帮助我。

最佳尝试:

static char[] rotate(char[] c, int z)
{
    char[] nc = new char[c.Length];
    for (int i = z; i < c.Length; i++)
    {
        nc[i - z] = c[i];
    }
    for (int i = 0; i < z; i++)
    {
        nc[i + z] = c[i];
    }
    return nc;
}

只需使用Array.Copy

Copies a range of elements in one Array to another Array and performs type casting and boxing as required.

public static void DoStuff<T>(T[]source, int z)
{
   var start = source[0..z];
   Array.Copy(source, z, source, 0, source.Length - z);
   Array.Copy(start, 0, source, source.Length - z, z);
}

测试

var chars = "asdfghjk".ToCharArray();

DoStuff(chars, 3);

Console.WriteLine(string.Join(", ", chars));

迭代器的另一种方式

public static IEnumerable<T> DoStuff<T>(T[]source, int z) 
   => source.Select((t, i) => source[(i + z) % source.Length]);

或者使用 for 循环

public static T[] DoStuff<T>(T[]source, int z)
{
   var result = new T[source.Length];
   for (int i = 0; i < source.Length; i++)
      result[i] = source[(i + z) % source.Length];
   return result;
}

超高效的零分配

public static unsafe void DoStuff(char[] source, int z)
{
   var start = stackalloc char[source.Length];
   fixed (char* pArray = source)
   {
      Buffer.MemoryCopy(pArray, start, z*sizeof(char), z * sizeof(char));
      Buffer.MemoryCopy(pArray+z, pArray, (source.Length-z)*sizeof(char) , (source.Length - z) * sizeof(char));
      Buffer.MemoryCopy(start, pArray+ (source.Length - z),  z * sizeof(char), z * sizeof(char));
   }
}

输出

f, g, h, j, k, a, s, d

注意:这缺少合适的输入验证和范围检查,以及描述性名称。我会把它留给你

您可以在一行中使用 LINQ 而无需像这样处理数组:

using System.Linq;

var letters = new[] { 'H', 'E', 'L', 'L', 'O' };

int posToRotate = 3;

var lettersRotated = letters.Skip(posToRotate).Concat(letters.Take(posToRotate)).ToArray();

Console.WriteLine(new string(lettersRotated));

假定 letters 已分配且不为空。

如果位置超过长度,则什么都不做,但可以先检查一下,避免处理(也可以检查负索引)。

我们skip the first N characters (to take the rest), then we add the first N characters we take.

我们叫ToArray because LINQ works on IEnumerable<> (and IQueryable<>), so execution is deferred到这里为止。

要替换原来的数组,只需写:

letters = letters.Skip(posToRotate).Concat(letters.Take(posToRotate)).ToArray();

输出

LOHEL

问题出在您的代码中的错误索引。
这是固定版本:

static char[] rotate(char[] c, int z)
{
    char[] nc = new char[c.Length];
    for (int i = z; i < c.Length; i++)
    {
        nc[i - z] = c[i];
    }
    for (int i = 0; i < z; i++)
    {
        nc[i + z - 1] = c[i]; // <-- Change here
    }
    return nc;
}

但是,更好的解决方案可能是使用 doubly-linked lists that handles movement of the array items to start/end better. .NET implementation of doubly-linked list is LinkedList Class. And here 您可以找到一些示例来说明如何做到这一点。