问题
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 arrayba
, 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