Распечатать двумерный массив в спиральном порядке - PullRequest
55 голосов
/ 07 апреля 2009

Как распечатать двумерный массив 5 × 5 в спиральном порядке?

Есть ли какая-нибудь формула, чтобы я мог напечатать массив любого размера в спиральном порядке?

Ответы [ 36 ]

77 голосов
/ 16 февраля 2011

Идея состоит в том, чтобы рассматривать матрицу как последовательность слоев, верхних правых слоев и нижних левых слоев. Чтобы распечатать матрицу по спирали, мы можем очистить слои от этой матрицы, распечатать очищенную часть и рекурсивно вызвать печать слева над частью. Рекурсия заканчивается, когда у нас больше нет слоев для печати. ​​

Матрица ввода:

1 2 3 4 
5 6 7 8
9 0 1 2   
3 4 5 6 
7 8 9 1

После отслоения верхнего правого слоя:

 1 2 3 4 
       8
5 6 7  2
9 0 1  6   
3 4 5  1 
7 8 9

После отслоения нижнего левого слоя от подматрицы:

   6 7
5  0 1   
9  4 5
3 
7 8 9 

После отслоения верхнего правого слоя от подматрицы:

    6 7
      1   
   0  5
   4

После отслоения нижнего левого слоя от подматрицы:

  0
  4

Рекурсия заканчивается.


Функции C:

// function to print the top-right peel of the matrix and 
// recursively call the print bottom-left on the submatrix.
void printTopRight(int a[][COL], int x1, int y1, int x2, int y2) {
    int i = 0, j = 0;

    // print values in the row.
    for(i = x1; i<=x2; i++) {
        printf("%d ", a[y1][i]);
    }

    // print values in the column.
    for(j = y1 + 1; j <= y2; j++)         {
        printf("%d ", a[j][x2]);
    }

    // see if more layers need to be printed.
    if(x2-x1 > 0) {
        // if yes recursively call the function to 
        // print the bottom left of the sub matrix.
        printBottomLeft(a, x1, y1 + 1, x2-1, y2);
    }
}

// function to print the bottom-left peel of the matrix and 
// recursively call the print top-right on the submatrix.
void printBottomLeft(int a[][COL], int x1, int y1, int x2, int y2) {
    int i = 0, j = 0;

    // print the values in the row in reverse order.
    for(i = x2; i>=x1; i--) {
        printf("%d ", a[y2][i]);
    }

    // print the values in the col in reverse order.
    for(j = y2 - 1; j >= y1; j--) {
        printf("%d ", a[j][x1]);
    }

    // see if more layers need to be printed.
    if(x2-x1 > 0) {
        // if yes recursively call the function to 
        // print the top right of the sub matrix.
        printTopRight(a, x1+1, y1, x2, y2-1);
    }
}

void printSpiral(int arr[][COL]) {
    printTopRight(arr,0,0,COL-1,ROW-1);
    printf("\n");
}
31 голосов
/ 17 июня 2014
  1. Pop верхний ряд
  2. Переставить и перевернуть вверх ногами (так же, как повернуть на 90 градусов против часовой стрелки)
  3. Перейти к 1

Код Python:

import itertools

arr = [[1,2,3,4],
       [12,13,14,5],
       [11,16,15,6],
       [10,9,8,7]]

def transpose_and_yield_top(arr):
    while arr:
        yield arr[0]
        arr = list(reversed(zip(*arr[1:])))

print list(itertools.chain(*transpose_and_yield_top(arr)))
23 голосов
/ 25 октября 2013

Я вижу, что никто не использовал только один for loop и без рекурсии в коде, и поэтому я хочу внести свой вклад.

Идея такова:

Представьте, что в точке (0,0) стоит черепаха, то есть в верхнем левом углу, обращенная на восток (вправо)

Она будет продолжать идти вперед , и каждый раз, когда она видит знак, черепаха поворачивает направо

Таким образом, если мы поместим черепаху в точку (0,0), направленную вправо, и если мы разместим знаки в соответствующих местах, черепаха будет пересекать массив по спирали.

Теперь проблема: «Где поставить знаки?»

Давайте посмотрим, куда мы должны поместить знаки (отмеченные # и цифры O):

For a grid that looks like this:
O O O O
O O O O
O O O O
O O O O

We put the signs like this:
O O O #
# O # O
O # # O
# O O #

For a grid that looks like this:
O O O
O O O
O O O
O O O

We put the signs like this:
O O #
# # O
O # O
# O #

And for a grid that looks like this:
O O O O O O O
O O O O O O O
O O O O O O O
O O O O O O O
O O O O O O O

We put the signs like this:
O O O O O O #
# O O O O # O
O # O O # O O
O # O O O # O
# O O O O O #

Мы можем видеть, что, если точка не находится в верхней левой части, знаки являются местами в точках, где расстояния до ближайшей горизонтальной границы и ближайшей вертикальной границы одинаковы , тогда как для верхняя левая часть, расстояние до верхней границы на единицу больше, чем расстояние до левой границы , причем приоритет отдается верхнему правому углу в случае горизонтального центрирования точки и верхнему левому краю в в случае, если точка расположена вертикально по центру.

Это можно легко реализовать в простой функции, взяв минимум (curRow и height-1-curRow), затем минимум (curCol и width-1-curCol) и сравните, если они совпадают. Но нам нужно учесть верхний левый регистр, то есть когда минимум равен curRow и curCol. В этом случае мы соответственно уменьшаем вертикальное расстояние.

Вот код C:

#include <stdio.h>

int shouldTurn(int row, int col, int height, int width){
    int same = 1;
    if(row > height-1-row) row = height-1-row, same = 0; // Give precedence to top-left over bottom-left
    if(col >= width-1-col) col = width-1-col, same = 0; // Give precedence to top-right over top-left
    row -= same; // When the row and col doesn't change, this will reduce row by 1
    if(row==col) return 1;
    return 0;
}

int directions[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
void printSpiral(int arr[4][4], int height, int width){
    int directionIdx=0, i=0;
    int curRow=0, curCol=0;
    for(i=0; i<height*width; i++){
        printf("%d ",arr[curRow][curCol]);
        if(shouldTurn(curRow, curCol, height, width)){
            directionIdx = (directionIdx+1)%4;
        }
        curRow += directions[directionIdx][0];
        curCol += directions[directionIdx][1];
    }
    printf("\n");
}

int main(){
    int arr[4][4]= {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
    printSpiral(arr, 4, 4);
    printSpiral(arr, 3, 4);
}

Какие выходы:

1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10
1 2 3 4 8 12 11 10 9 5 6 7
8 голосов
/ 17 ноября 2012

Вот три интересных способа

  1. Чтение по спирали можно рассматривать как змею, движущуюся к границе и включающую удар по границе или самому себе (я нахожу это элегантным и наиболее эффективным, если использовать один цикл из N итераций)

    ar = [
         [ 0,  1,  2,  3, 4],
         [15, 16, 17, 18, 5],
         [14, 23, 24, 19, 6],
         [13, 22, 21, 20, 7],
         [12, 11, 10, 9, 8]]
    
    def print_spiral(ar):
        """
        assuming a rect array
        """
        rows, cols = len(ar), len(ar[0])
        r, c = 0, -1 # start here
        nextturn = stepsx = cols # move so many steps
        stepsy = rows-1
        inc_c, inc_r = 1, 0 # at each step move this much
        turns = 0 # how many times our snake had turned
        for i in range(rows*cols):
            c += inc_c
            r += inc_r 
    
            print ar[r][c],
    
            if i == nextturn-1:
                turns += 1
                # at each turn reduce how many steps we go next
                if turns%2==0:
                    nextturn += stepsx
                    stepsy -= 1
                else:
                    nextturn += stepsy
                    stepsx -= 1
                # change directions
                inc_c, inc_r = -inc_r, inc_c  
    
    print_spiral(ar)
    

выход: * +1010 *

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  1. Рекурсивным подходом было бы напечатать внешний слой и вызвать ту же функцию для внутреннего прямоугольника, например

    def print_spiral(ar, sr=0, sc=0, er=None, ec=None):
        er = er or len(ar)-1
        ec = ec or len(ar[0])-1
    
        if sr > er or sc > ec:
            print
            return
    
        # print the outer layer
        top, bottom, left, right = [], [], [], []
        for c in range(sc,ec+1):
            top.append(ar[sr][c])
            if sr != er:
                bottom.append(ar[er][ec-(c-sc)])
    
        for r in range(sr+1,er):
            right.append(ar[r][ec])
            if ec != sc:
                left.append(ar[er-(r-sr)][sc])
    
        print " ".join([str(a) for a in top + right + bottom + left]),
    
        # peel next layer of onion
        print_spiral(ar, sr+1, sc+1, er-1, ec-1)
    

Наконец, вот небольшой фрагмент, чтобы сделать это, не эффективно, но весело :), в основном он печатает верхний ряд, вращает весь прямоугольник против часовой стрелки и повторяет

def print_spiral(ar):
    if not ar: return
    print " ".join(str(a) for a in ar[0]),
    ar = zip(*[ reversed(row) for row in ar[1:]])
    print_spiral(ar)
6 голосов
/ 05 марта 2013

Эта программа работает для любой n * n матрицы.

public class circ {
    public void get_circ_arr (int n,int [][] a)
    {
        int z=n;
        {
            for (int i=0;i<n;i++)
            {
                for (int l=z-1-i;l>=i;l--)
                {
                    int k=i;
                    System.out.printf("%d",a[k][l]);
                }           

                for (int j=i+1;j<=z-1-i;j++)
                {
                    int k=i;
                    {
                        System.out.printf("%d",a[j][k]);
                    }
                }

                for (int j=i+1;j<=z-i-1;j++)
                {
                    int k=z-1-i;
                    {
                        System.out.printf("%d",a[k][j]);
                    }
                }

                for (int j=z-2-i;j>=i+1;j--)
                {
                    int k=z-i-1;        
                    {
                        System.out.printf("%d",a[j][k]);
                    }
                }
            }
        }
    }
}

Надеюсь, это поможет

5 голосов
/ 30 декабря 2013

Я был одержим этой проблемой, когда изучал Ruby. Это было лучшее, что я мог сделать:

def spiral(matrix)
  matrix.empty? ? [] : matrix.shift + spiral(matrix.transpose.reverse)
end

Вы можете проверить некоторые другие мои решения, вернувшись к ревизиям в этом gist . Кроме того, если вы перейдете по ссылке, от которой я получил ответ, вы найдете и другие умные решения. Действительно интересная проблема, которая может быть решена несколькими изящными способами - особенно в Ruby.

3 голосов
/ 27 ноября 2014

Решение JavaScript:

var printSpiral = function (matrix) {
  var i;
  var top = 0;
  var left = 0;
  var bottom = matrix.length;
  var right = matrix[0].length;

  while (top < bottom && left < right) {

    //print top 
    for (i = left; i < right; i += 1) {
      console.log(matrix[top][i]);
    }
    top++;

    //print right column
    for (i = top; i < bottom; i += 1) {
      console.log(matrix[i][right - 1]);
    }
    right--;

    if (top < bottom) {
      //print bottom
      for (i = right - 1; i >= left; i -= 1) {
        console.log(matrix[bottom - 1][i]);
      }
      bottom--;
    }

    if (left < right) {
      //print left column
      for (i = bottom - 1; i >= top; i -= 1) {
        console.log(matrix[i][left]);
      }
      left++;
    }
  }
};
2 голосов
/ 31 октября 2011

Одно решение включает направления вправо, влево, вверх, вниз и их соответствующие пределы (индексы). Как только первая строка напечатана, и направление изменяется (справа) на вниз, строка отбрасывается путем увеличения верхнего предела. После того, как последний столбец напечатан, а направление меняется влево, столбец отбрасывается уменьшением правого предела ... Подробности можно увидеть в не требующем пояснений коде C.

#include <stdio.h>
#define N_ROWS 5
#define N_COLS 3

void print_spiral(int a[N_ROWS][N_COLS])
{
    enum {up, down, left, right} direction = right;
    int up_limit = 0,
        down_limit = N_ROWS - 1,
        left_limit = 0,
        right_limit = N_COLS - 1,
        downcount = N_ROWS * N_COLS,
        row = 0,
        col = 0;

    while(printf("%d ", a[row][col]) && --downcount)
        if(direction == right)
        {
            if(++col > right_limit)
            {
                --col;
                direction = down;
                ++up_limit;
                ++row;
            }
        }
        else if(direction == down)
        {
            if(++row > down_limit)
            {
                --row;
                direction = left;
                --right_limit;
                --col;
            }
        }
        else if(direction == left)
        {
            if(--col < left_limit)
            {
                ++col;
                direction = up;
                --down_limit;
                --row;
            }
        }
        else /* direction == up */
            if(--row < up_limit)
            {
                ++row;
                direction = right;
                ++left_limit;
                ++col;
            }
}

void main()
{
    int a[N_ROWS][N_COLS] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    print_spiral(a);
}

Ссылка для тестирования и загрузки

.

2 голосов
/ 25 октября 2013

Двумерная матрица N * N - квадратная матрица

Идея:

Мы должны пройти в четырех разных направлениях, чтобы пройти как спираль. Мы должны пройти через матрицу, как только закончится один слой спирали. Итак, нам нужно 5 петель, 4 петли для прохождения, как по спирали, и 1 петля для прохождения через слои.

public void printSpiralForm(int[][] a, int length)
{

  for( int i = 0 , j = length-1 ; i < j ; i++ , j-- )
  {

    for( int k = i ; k < j ; k++ )
    {
      System.out.print( a[i][k] + " " ) ;
    }

    for( int k = i ; k < j ; k++ )
    {
      System.out.print(a[k][j] + " ");
    }

    for( int k = j ; k > i ; k-- )
    {
      System.out.print(a[j][k] + " ") ;
    }

    for( int k = j ; k > i ; k-- )
    {
      System.out.print( a[k][i] + " " ) ;
    }

  }

  if ( length % 2 == 1 )
  {
    System.out.println( a[ length/2 ][ length/2 ] ) ;
  }

}
2 голосов
/ 07 февраля 2016

Просто будь проще ->

public class spiralMatrix {

public static void printMatrix(int[][] matrix, int rows, int col)
{
    int rowStart=0;
    int rowEnd=rows-1;
    int colStart=0;
    int colEnd=col-1;

    while(colStart<=colEnd && rowStart<=rowEnd)
    {
        for(int i=colStart;i<colEnd;i++)
            System.out.println(matrix[rowStart][i]);

        for(int i=rowStart;i<rowEnd;i++)
            System.out.println(matrix[i][colEnd]);

        for(int i=colEnd;i>colStart;i--)
            System.out.println(matrix[rowEnd][i]);

        for(int i=rowEnd;i>rowStart;i--)
            System.out.println(matrix[i][colStart]);
        rowStart++;
        colEnd--;
        rowEnd--;
        colStart++;

    }

}
public static void main(String[] args){

    int[][] array={{1,2,3,4},{5,6,7,8}};
    printMatrix(array,2,4);
}

}

...