按任意步长旋转数组,而不创建第二个数组

时间:2012-03-09 14:10:48

标签: java arrays performance algorithm

因此,对于步长为1,我想要数组:

{1, 2, 3, 4}

成为:

{4, 1, 2, 3}

对于大小为2的步骤,结果将是:

{3, 4, 1, 2}

这是我现在使用的代码:

private static int[] shiftArray(int[] array, int stepSize) {
  if (stepSize == 0)
     return array;

  int shiftStep = (stepSize > array.length ? stepSize % array.length : stepSize);

  int[] array2 = new int[array.length];
  boolean safe = false;
  for (int i = 0; i < array.length; i++) {
     if (safe) {
        array2[i] = array[i - shiftStep];
     }
     else {
        array2[i] = array[array.length - shiftStep + i];
        safe = (i+1) - shiftStep >= 0;
     }
  }
  return array2;
}

代码运行良好,但是可以在不创建辅助数组(上面的代码中是array2)的情况下实现这一点吗?

谢谢!

6 个答案:

答案 0 :(得分:11)

您可以在不创建大型数组的情况下执行此操作:

// void return type as it shifts in-place
private static void shiftArray(int[] array, int stepSize) {
    // TODO: Cope with negative step sizes etc
    int[] tmp = new int[stepSize];
    System.arraycopy(array, array.length - stepSize, tmp, 0, stepSize);
    System.arraycopy(array, 0, array, stepSize, array.Length - stepSize);
    System.arraycopy(tmp, 0, array, 0, stepSize);
}

因此,对于100,000个数组和10的步长,它会创建一个10个元素的数组,将最后10个元素复制到其中,将第一个999,990个元素复制到后面,然后从临时数组复制回< em>开始数组。

答案 1 :(得分:3)

不使用i ++,但是i + = shiftSize和几个循环(它们的数量等于array.length和shifSize的gcd

然后你只需要一个int作为缓冲区,执行时间几乎相同。

答案 2 :(得分:3)

你可以用几个循环来做,但这并不容易。在这种情况下,使用递归更简单。

public static void main(String... args) {
    for (int i = 0; i < 12; i++) {
        int[] ints = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
        rotateLeft(ints, i);
        System.out.println(Arrays.toString(ints));
    }
}

public static void rotateLeft(int[] array, int num) {
    rotateLeft(array, num, 0);
}

private static void rotateLeft(int[] array, int num, int index) {
    if (index >= array.length) return;
    int tmp = array[(index + num) % array.length];
    rotateLeft(array, num, index + 1);
    array[index] = tmp;
}

打印

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1]
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]
[5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4]
[6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5]
[7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6]
[8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7]
[9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8]
[10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

答案 3 :(得分:2)

是的,有可能,您只需临时存储阵列附加的一个元素。 基本上你想要做的是:

  1. 将最后一个元素存储在tmp var
  2. 将所有元素向右移动一个从第二个到最后一个元素开始的元素
  3. sotre tmp var as first element
  4. 从步骤1开始重复,具体取决于您的步骤

答案 4 :(得分:2)

这未经过测试......

public void rotateByStep(int[] array, int step) {
    step = step % array.length;
    if (step == 0) {
        return;
    }
    int pos = step;
    int tmp = array[0];
    boolean inc = array.length % step == 0;
    for (int i = 0; i < array.length; i++) {
        int tmp2 = array[pos];
        array[pos] = tmp;
        tmp = tmp2;
        pos = (pos + step) % array.length;
        if (inc && pos < step) {
            array[pos] = tmp;
            pos++;
            tmp = array[pos];
        }
    }
}

我试图实施的想法如下:

  • 如果step不是length的因子,则从posstep开始递增索引(length)在length次迭代后,零将访问每个数组元素。

  • 如果steplength的因子,则索引(如上所述递增)将在length / step次迭代后返回其起始点。但是如果然后增加1,则可以处理从1开始的循环,然后是2,依此类推。在length次迭代后,我们将访问每个数组元素一次。

当我们循环遍历元素索引时,其余的只是在元素值上晃动...当我们增加到下一个周期时进行一些调整。

其他完整的解决方案的优点是它们更容易理解,但是这个解决方案不需要额外的堆存储(即没有临时数组),并且在array.length循环迭代中完成工作。

答案 5 :(得分:0)

在n-1次迭代中

#include <stdio.h>

    int main(int argc, char **argv) {
        int k = 0, x = 0;
        int a[] = {-5,-4,-1,0,1,2,30,43,52,68,700,800,9999};
        int N = 0, R = 57; /*R = No of rotations*/
        int temp = 0, temp2  = 0, start = 0, iter = 0;

        x = 0;
        temp2 = a[x];

        N = sizeof(a) / sizeof(a[0]);
        for ( k = 0; k < N - 1; k++) {
            x = x + R;
            while ( x >= N ) {
                x = x - N;
            }
            temp = a[x];
            a[x] = temp2;
            temp2 = temp;
            if ( x == start ) {
                start = start + 1;
                x = x + 1;
                temp2 = a[x];
            }
            iter++;
        }
        a[start] = temp2;
        for ( k = 0; k < N; k++) {
            printf(" %d", a[k]);
        }
        printf("\n");
        printf("Done in %d iteration\n", iter);
        return 0;
    }