Rotate array left or right by a set number of positions in o(n) complexity

亡梦爱人 提交于 2019-12-22 09:52:14

问题


I want to write a program that shifts an array by a set number of positions right or left based on the user's input (positive ->, negative <-). The program has to have O(n) complexity. I've written it this way but it doesn't work as it should. In the example the output should be "2, 3, 4, 5, 6, 1" but in my version is "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];
        }
    }
}

Thank you.


回答1:


Jon Bentley in Programming Pearls Column 2 describes what has came to be known as the most elegant, efficient solution.

The rotation algorithm uses a function reverse() that reverses subsequences of the array. Quoting from the column:

Let's view the problem as transforming the array ab into the array ba, but let's also assume that we have a function that reverses the elements in a specified portion of the array. Starting with ab, we reverse a to get a_r b, reverse b to get a_r b_r, and then reverse the whole thing to get (a_r b_r)_r, which is exactly ba.

This is what you need. The input from the user defines the place where you will partition the array into two blocks A and B. Here's my implementation:

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);
}

I tested it and it's working. Also, note how negative rotations are handled: rotating an array of size elements amt to the left (i.e. with negative values) is the same as rotating it size+amt to the right.

Enjoy the elegant code, and don't forget to include credits in a comment (to Jon Bentley, of course).




回答2:


For right rotate use:

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];
}

For left rotate use:

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];
}

where a[n] is the array and d is the number of positions you want to rotate.




回答3:


you are just swapping elements positions: element at position 1 is put at position 6 and vice versa... You should rewrite the last part. There are two ways to go:

  • allocate a new array and copy your values one by one
  • just save one value in tmp, and shift the others



回答4:


The trivial approach would be to rotate, but looking beyond that, why not try just repositioning the elements of the array/list.

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)

Thats right rotation, for left rotation just flip

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



来源:https://stackoverflow.com/questions/22078728/rotate-array-left-or-right-by-a-set-number-of-positions-in-on-complexity

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!