176 votes

Boucle en spirale

Un ami avait besoin d'un algorithme qui lui permettrait de parcourir les éléments d'une matrice NxM (N et M sont impairs). J'ai proposé une solution, mais je voulais voir si mes collègues de SO pouvaient proposer une meilleure solution.

Je poste ma solution en tant que réponse à cette question.

Résultat exemple:

Pour une matrice 3x3, le résultat devrait être:

(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1)

matrice 3x3

De plus, l'algorithme devrait prendre en charge les matrices non carrées, donc par exemple pour une matrice 5x3, le résultat devrait être:

(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)

matrice 5x3

0 votes

Pouvez-vous expliquer ce que vous voulez pour les matrices non carrées ? Votre solution a un "saut" de (2, 1) à (-2, 1) -- est-ce voulu ? [Par exemple, pour une matrice 7x3, elle aurait deux "sauts" supplémentaires, et pour une matrice (2k+1)x3, elle aurait 2k-3 sauts ?]

3 votes

Oui, les sauts sont intentionnels. J'ai mis à jour la question avec une image de matrice 5x3. Comme vous pouvez le voir sur l'image, nous sautons les lignes du haut et du bas.

0 votes

D'accord, alors votre propre code semble le plus propre. Et bien que cela soit hors sujet : comment avez-vous généré ces images? :)

72voto

Can Berk Güder Points 39887

Voici ma solution (en Python) :

def spiral(X, Y):
    x = y = 0
    dx = 0
    dy = -1
    for i in range(max(X, Y)**2):
        if (-X/2 < x <= X/2) and (-Y/2 < y <= Y/2):
            print (x, y)
            # FAIRE DES CHOSES...
        if x == y or (x < 0 and x == -y) or (x > 0 and x == 1-y):
            dx, dy = -dy, dx
        x, y = x+dx, y+dy

1 votes

C'est la meilleure façon de l'écrire, autant que je puisse le voir. La seule amélioration possible serait de le rendre O(MN) au lieu de O(max(M,N)^2) en sautant directement ceux (x,y) qui ne seront pas imprimés, mais cela rendrait le code un peu plus moche.

0 votes

Je suis en train d'optimiser ma solution et elle est assez proche de ce que vous avez déjà. Je pense que c'est une assez bonne solution. En plus de la suggestion de ShreevatsaR et des choses comme ne pas calculer x/2 et y/2 à chaque itération, il n'y a pas grand chose à améliorer sauf le style.

0 votes

Avez-vous des solutions pour matlab ?

36voto

Tom J Nowell Points 1915

Quelqu'un connaît C++? Traduction rapide depuis python, postée pour complétude

void Spiral( int X, int Y){
    int x,y,dx,dy;
    x = y = dx =0;
    dy = -1;
    int t = std::max(X,Y);
    int maxI = t*t;
    for(int i =0; i < maxI; i++){
        if ((-X/2 <= x) && (x <= X/2) && (-Y/2 <= y) && (y <= Y/2)){
            // FAIRE DES CHOSES...
        }
        if( (x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1-y))){
            t = dx;
            dx = -dy;
            dy = t;
        }
        x += dx;
        y += dy;
    }
}

0 votes

Vous pouvez également utiliser des s et des ds comme je le fais pour détecter les coins, ce qui élimine la nécessité d'une énorme condition if

1 votes

Une modification a été proposée ici pour ce message. Bien que la modification ait été rejetée car elle modifie le sens de votre message, vous voudrez peut-être envisager d'incorporer les changements suggérés s'ils sont pertinents.

15voto

Andrea Ambu Points 6479

J'adore les générateurs de Python.

def spiral(N, M):
    x,y = 0,0   
    dx, dy = 0, -1

    for dumb in xrange(N*M):
        if abs(x) == abs(y) and [dx,dy] != [1,0] or x>0 and y == 1-x:  
            dx, dy = -dy, dx            # coin, changer de direction

        if abs(x)>N/2 or abs(y)>M/2:    # rectangle
            dx, dy = -dy, dx            # changer de direction
            x, y = -y+dx, x+dy          # sauter

        yield x, y
        x, y = x+dx, y+dy

Test avec:

print 'Spirale 3x3:'
for a,b in spiral(3,3):
    print (a,b),

print '\n\nSpirale 5x3:'
for a,b in spiral(5,3):
    print (a,b),

Vous obtenez:

Spirale 3x3:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) 

Spirale 5x3:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)

8voto

JHolta Points 555

Tentative de golf "Code" spirale en Java, basée sur la variante C++.

public static void Spiral(int X, int Y) {
    int x=0, y=0, dx = 0, dy = -1;
    int t = Math.max(X,Y);
    int maxI = t*t;

    for (int i=0; i < maxI; i++){
        if ((-X/2 <= x) && (x <= X/2) && (-Y/2 <= y) && (y <= Y/2)) {
            System.out.println(x+","+y);
            //FAIRE QUELQUE CHOSE
        }

        if( (x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1-y))) {
            t=dx; dx=-dy; dy=t;
        }   
        x+=dx; y+=dy;
    }
}

4voto

Starkii Points 729

Voici ma solution (En Ruby)

def spiral(xDim, yDim)
   sx = xDim / 2
   sy = yDim / 2

   cx = cy = 0
   direction = distance = 1

   yield(cx,cy)
   while(cx.abs <= sx || cy.abs <= sy)
      distance.times { cx += direction; yield(cx,cy) if(cx.abs <= sx && cy.abs <= sy); } 
      distance.times { cy += direction; yield(cx,cy) if(cx.abs <= sx && cy.abs <= sy); } 
      distance += 1
      direction *= -1
   end
end

spiral(5,3) { |x,y|
   print "(#{x},#{y}),"
}

0 votes

Encore O(max(n,m)^2), mais joli style.

1 votes

Direction=-direction au lieu de direction*=-1? si vous jouiez au golf d=-d est plus court que d*=-1 aussi

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X