2010-12-16 186 views
23

Comment faire pivoter un tableau d'entiers de i fois en utilisant la fonction swap uniquement en temps linéaire.Algorithme de rotation d'une matrice en temps linéaire

+5

Veuillez développer votre question un peu. Quelle dimension a le tableau? Que voulez-vous dire par "rotation d'un tableau"? Donnez un exemple d'entrée et de sortie. Pensez à utiliser des signes de ponctuation et des majuscules, le cas échéant. –

+0

Qu'avez-vous essayé? Comment ça ne marche pas? IOW, vous devez essayer d'abord avant de vous aider (nous n'allons pas l'écrire à partir de vous) – KevinDTimm

+0

@sven supposons que le tableau d'entrée est le tableau de sortie {1,2,3,4,5} après qu'une rotation à droite est {5, 1,2,3,4}. –

Répondre

43

Vous pouvez le faire dans le temps linéaire en utilisant un assistant inverse().

// rotate array of size=size, by n positions 
void rotate(int array[], int size, int n) 
{ 
    // reverse array[0...size-1] 
    reverse(array, 0, size-1); 

    // reverse A[0...n-1] 
    reverse(array, 0, n-1); 

    // reverse A[n...size-1] 
    reverse(array, n, size-1); 
} 

// reverse elements in the array[pos_from ... pos_to] 
void reverse(int array[], int pos_from, int pos_to) 
{ 
    ... 
} 

La mise en œuvre au moyen de swaps reverse(int array[], int pos_from, int pos_to) est laissé comme un exercice pour le lecteur. Astuce: Cela peut être fait en temps linéaire.

+1

Je suis juste curieux de savoir pourquoi ça marche tout le temps – daydreamer

+2

@daydreamer Vous pouvez vous référer à ce document: http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf Si vous échangez le 2ème et 3e inverse dans le code de Sanjit, c'est plus facile à comprendre. –

+3

Le lien ne fonctionne pas. Pouvez-vous fournir un lien avec une preuve pour cette méthode? – Daggerhunt

1

une naïve mise en œuvre de pseudocode:

for (n = 0; n < i; n++) { 
    for (j = array.length-1; j > n; j--) 
     swap(j, j-1) 
} 

se déplace à plusieurs reprises le dernier élément à l'avant, l'arrêt avant de se déplacer quoi que ce soit déplacé auparavant à l'avant

+1

J'ai essayé même soln mais je le veux dans o (n) –

+10

@prp - Peut-être mentionné dans la question alors, hein? –

0

pourquoi seule fonction d'échange?

O (n) dans le temps et l'espace:

var rotateCount = 1; 
var arr = new Array(1,2,3,4,5,6,7,8,9,10); 

tmp = new Array(arr.length); 
for (var i = 0; i<arr.length; i++) 
    tmp[(i+rotateCount)%arr.length]=arr[i]; 
arr = tmp; 

alert(arr); 
+0

pourquoi voter en bas? Ce code fonctionne! – Stuck

+0

Ce code ne fonctionne pas. Essayez rotateCount = 8, il produit: 9,10,2,3,4,5,6,7,8,1. – Nixuz

+0

@Nixuz: correction de ce bug – Stuck

18

Disons que nous avons une fonction appelée arr_reverse(arr,i,j) qui inverse les éléments du tableau arr entre l'indice i et j en utilisant la fonction swap.

Exemple:

arr = {1,2,3,4,5} 
i = 0 
j = 2 

alors la fonction retournera:

{3,2,1,4,5} 
^^^^^ 

La mise en œuvre de cette fonction est simple et est O(N).

Utilisons maintenant cette fonction pour faire pivoter la matrice.

arr  = {1,2,3,4,5} // input array 
k  = 2 // amount of right rotation 
result = {4,5,1,2,3} // expected result 
l  = 5 // length of array. 

Step 1: Call arr_reverse(arr,l-k,l-1) which is arr_reverse(arr,3,4) 
we get {1,2,3,5,4} 
       ^^^ 

Step 2: Call arr_reverse(arr,0,l-k-1) which is arr_reverse(arr,0,2) 
we get {3,2,1,5,4} 
     ^^^^^  

Step 3: Call arr_reverse(arr,0,l-1) which is arr_reverse(arr,0,4) 
we get {4,5,1,2,3} 
     ^^^^^^^^^ 

L'ensemble du processus utilise arr_reverse 3 fois, ce qui en fait O(N)

+0

Je pense que vous avez fait une faute de frappe aux étapes 2 et 3 de votre exemple, où vous montrez le résultat. Vous avez les 4 et 5 retournés de ce qu'ils devraient être. – Nixuz

+0

@Nixuz: Merci de le remarquer. – codaddict

1

Mieux utiliser une fonction directe et simple, la complexité N:

int rotate(int* a,int DIM,int rn,int* b) { 
    int i; //counter 
    for(i=0;i<DIM;i++){ // looping through the array 
     b[(i+rn)%len]=a[i]; // copying the values in the b array=a shifted with rn(+ for right or - for left shifting 
} 
2

En utilisant O temps linéaire (2N + m), et l'espace constant O (4). m = GCD (n, p)

Il est jusqu'à 50% plus rapide que l'approche de permutation, car l'échange nécessite d'écrire O (N) fois à un moment.

http://www.eis.mdx.ac.uk/staffpages/r_bornat/oldteaching/I2A/slides%209%20circshift.pdf

for (m=0, count=0; count!=n; m++) { 
    type t=A[m]; 
    for (i=m, j=m+p; j!=m; i=j, j = j+p<n ? j+p : j+p-n, count++) 
     A[i]=A[j]; 
    A[i]=t; count++; 
} 
4

est ici une meilleure solution, d'une autre nature que les autres. Cela implique moins d'échanges de tableaux que les autres.Python:

import fractions 
# rotates an array in-place i positions to the left, in linear time 
def rotate(arr,i): 
    n = len(arr) 
    reps = fractions.gcd(n,i) 
    swaps = n/reps 
    for start in xrange(reps): 
     ix = start 
     tmp = arr[ix] 
     for s in xrange(swaps-1): 
      previx = ix 
      ix = (ix + i) % n 
      arr[previx] = arr[ix] 
     arr[ix] = tmp 
    return arr 
0
/* 
* To change this template, choose Tools | Templates 
* and open the template in the editor. 
*/ 
package rotateinlineartime; 

/** 
* 
* @author Sunshine 
*/ 
public class Rotator { 

    void reverse(int a[], int n) { 
     for (int i = 0; i <= n - 1; i++) { 
      int temp; 
      temp = a[i]; 
      a[i] = a[n - 1]; 
      a[n - 1] = temp; 
      n--; 
     } 

     printArray(a); 
    } 

    void printArray(int a[]) { 
     for (int i = 0; i < a.length; i++) { 
      System.out.println(a[i]); 
     } 
    } 
} 
0
/* Q: How can we shift/rotate an array in place? 
A: "in place" means O(1) space complexity, so we need to do some trick 
*/ 

#include <iostream> 
#include <algorithm> 
using namespace std; 

void ArrayRotate(int a[], int n, int k) 
{ 
    if (n < 1 || k % n == 0) return; 

    k %= n; 
    if (k < 0) k += n; 

    reverse(a, a+k); 
    reverse(a+k, a+n); 
    reverse(a, a+n); 
} 

void PrintArray(int a[], int n) 
{ 
    for (int i = 0 ; i < n; ++i) 
     cout << a[i] << " "; 
    cout << endl; 
} 

int main() 
{ 
    int a[] = { 1, 2 , 3, 4, 5 }; 
    int n = sizeof(a)/sizeof (a[0]); 

    PrintArray(a, n); 
    ArrayRotate(a, n, 2); 
    PrintArray(a, n); 

    return 0; 
} 
/* Output: 
1 2 3 4 5 
3 4 5 1 2 
*/ 
0

l'aide de swaps seulement, suivant est un implémentation C++

template<class T> 
void rotate_array(std::vector<T> *array, int i) { 
    int n = array->size(); 
    i = i % n; 
    int gcd_n_i = gcd(i, n); 
    for (int j = 0; j < gcd_n_i; j++) { 
    T first_element = array->at(j); 
    for (int k = j; (k + i) % n != j; k = (k + i) % n) { 
     std::swap(array->at(k), array->at((k + i) % n)); 
    } 
    } 
} 

Vous pouvez en lire davantage à http://pointer-overloading.blogspot.in/2013/09/algorithms-rotating-one-dimensional.html

0
void reverse_array(int a[], int start, int end){ 

    while(start < end){  
      int temp = a[start]; 
      a[start] = a[end]; 
      a[end] = temp; 
      start++; 
      end--; 
    } 

}

void rotate_array(int a[], int pivot, int len){ 
    int i; 
    /*Reverse the whole array */ 
    reverse_array(a, 0, len); 

    /* Reverse from 0 to pivot and pivot to end */ 
    reverse_array(a,0, pivot); 
    reverse_array(a,pivot+1,len); 

}