以o(n)复杂度向左或向右旋转一组位置

时间:2014-02-27 19:43:12

标签: c rotation shift

我想编写一个程序,根据用户的输入(正 - >,负&lt ;-)将数组向右或向左移动一定数量的位置。该程序必须具有O(n)复杂性。我是用这种方式写的,但它不能正常工作。在示例中,输出应为“2,3,4,5,6,1”,但在我的版本中为“6,2,3,4,5,1”。

#include <stdio.h>
#include <string.h>
#include <math.h>

void rotate(int *array, int N, int D);

int main(){
    int i;
    int array[] = {1, 2, 3, 4, 5, 6};

    rotate(array, sizeof(array)/sizeof(int), 5);

    for(i=0; i<sizeof(array)/sizeof(int); i++)
        printf("%d\t", array[i]);

    return 0;
}

void rotate(int *array, int N, int D){
    int i, j, *tmp, d;

    tmp = malloc(abs(D) * sizeof(int));

    if(D<0){
        d = abs(D);
        for(i=d; i<N; i++){
            tmp[i%d] = array[i];
            array[i] = array[i-d];
            array[i-d] = tmp[i%d];
        }
    }
    if(D>0){
        for(i=(N-D-1); i>=0; i--){
            tmp[i%D] = array[i];
            array[i] = array[i+D];
            array[i+D] = tmp[i%D];
        }
    }
}

谢谢。

4 个答案:

答案 0 :(得分:14)

编程珍珠专栏2中的Jon Bentley描述了最优雅,最有效的解决方案。

  

旋转算法使用反转的函数reverse()   数组的子序列。引自专栏:

     

让我们将问题视为将数组ab转换为数组   ba,但我们也假设我们有一个可以反转的功能   数组的指定部分中的元素。从ab开始,我们   反转a得到a_r b,反转b得到a_r b_r,然后反转   得到的整个事情(a_r b_r)_r,这正是ba。

这就是你需要的。来自用户的输入定义了将数组分区为两个块A和B的位置。这是我的实现:

void reverse(int a[], int sz) {
  int i, j;
  for (i = 0, j = sz; i < j; i++, j--) {
    int tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;
  }
}

void rotate(int array[], int size, int amt) {
  if (amt < 0)
    amt = size + amt;
  reverse(array, size-amt-1);
  reverse(array+size-amt, amt-1);
  reverse(array, size-1);
}

我测试了它并且它正在工作。另外,请注意如何处理负旋转:将size元素amt数组向左旋转(即使用负值)与向右旋转size+amt相同。

享受优雅的代码,不要忘记在评论中加入学分(当然是Jon Bentley)。

答案 1 :(得分:2)

正确旋转使用:

temp[0]=a[0];
for(i=1;i<=n;i++)
{
    temp[i%2]=a[(i*d)%n];
    a[(i*d)%n]=temp[(i+1)%2];
}

左旋转使用:

temp[0]=a[0];
for(i=1;i<=n;i++)
{
    temp[i%2]=a[(i*(n-d))%n];
    a[(i*(n-d))%n]=temp[(i+1)%2];
}

其中a [n]是数组,d是要旋转的位置数。

答案 2 :(得分:1)

你只是交换元素位置:位置1的元素放在位置6,反之亦然......你应该重写最后一部分。有两种方法:

  • 分配一个新数组并逐个复制您的值
  • 只需在tmp中保存一个值,然后移动其他值

答案 3 :(得分:0)

最简单的方法是旋转,但除此之外,为什么不尝试仅重新定位数组/列表的元素。

def circularArrayRotation(a, k):
    k=k%len(a)
    b=a[len(a)-k:len(a)]
    #print(b)
    a=b+a[0:len(a)-k]
    print(a)

那是右旋,对于左旋只需翻转

b=a[k:len(a)] and a=b+a[0:k]