Step-by-Step Guide to Printing a 2D Array in Spiral Order

Nitish Kumar Singh

Jan 25, 2025

Printing a 2D array in spiral order is a common problem in practicing data structures and algorithms that helps us understand and write logical code.

Printing a 2D Array in Spiral Order

When we write code for this problem, we can understand how to use loops and conditions according to the problem. In this post, we are going to understand each step for building logic for this problem and write a Java method that prints the given 2D array spirally.

Before anything, first, see and understand what happens when we move spirally in a 2D array. When we move spirally in a 2D array, the below things happen:

  • First, we move on the top edge with a fixed row index, and the column index increases up to endCol.
  • Then, we move on the right edge with a fixed column index, and the row index increases up to endRow.
  • Then, on the bottom edge with a fixed row, the column index decreases up to startCol.
  • Finally, on the left edge with a fixed column, the row index decreases up to startRow + 1.

Here, startRow, endRow, startCol, and endCol are indices of the edges of one full spiral round, and they change after each spiral round, with startRow and startCol increasing by 1, and endRow and endCol decreasing by 1.

Using the above information, we have to build logic. This problem can be solved with two different approaches.

First, we run a loop for n times, where n is the number of spiral rounds we can move. The second approach is to run a loop for the number of cells in the given array. We will discuss both approaches and write code for them.

Round-by-Round Spira Movement

In this approach, we will focus on how many spiral rounds we can move using a while loop, and under this while loop, we print all found boundaries of one spiral round using four inner for loops. To write the code, we need to understand the points below:

  • The first question is how to make the condition for a while loop. In the above-given picture, we can see spiral rounds are possible until startRow <= endRow and startCol <= endCol, where equality is possible when the number of rows, columns, or both are odd.
  • What is the condition for the 4 for loops? The loops for printing the top, right, bottom, and left edges run from startCol to endCol, startRow+1 to endRow, endCol-1 to startCol, and endRow-1 to startRow+1 accordingly.
  • After printing each spiral round, we increase startRow and startCol by 1 and decrease endRow and endCol by 1 to move to the inner spiral round.

So, the complete Java code for printing using this approach is as below.

public static void printSpiralByRoundWise(int[][] matrix) {
    int startRow = 0, endRow = matrix.length - 1;
    int startCol = 0, endCol = matrix[0].length - 1;

    while (startRow <= endRow && startCol <= endCol) {
        // Print the top row (left to right)
        for (int col = startCol; col <= endCol; col++) {
            System.out.print(matrix[startRow][col] + "  ");
        }
        // Because right edge print from startRow+1
        startRow++;

        // Print the rightmost column (top to bottom)
        for (int row = startRow; row <= endRow; row++) {
            System.out.print(matrix[row][endCol] + "  ");
        }
        // Because bottom edge print from endCol-1
        endCol--;

        // Print the bottom row (right to left)
        // The startRow <= endRow is insure not repeat printing of same eadge in odd numbers of rows
        if (startRow <= endRow) {
            for (int col = endCol; col >= startCol; col--) {
                System.out.print(matrix[endRow][col] + "  ");
            }
            // Because left edge print from endRow-1
            endRow--;
        }

        // Print the leftmost column (bottom to top)
        // The startCol <= endCol is insure not repeat printing of same eadge in odd numbers of columns
        if (startCol <= endCol) {
            for (int row = endRow; row >= startRow; row--) {
                System.out.print(matrix[row][startCol] + "  ");
            }
            // For moving to next inner spiral round
            startCol++;
        }
    }
}

In the above code, we add loops that print the bottom and left edges in conditions to avoid repeated printing. For example, when the number of rows is 3, two rows are already printed in the first spiral round, and startRow increases to 1, while endRow decreases to 1.

So, in the second spiral round, only one edge is available, which is the top. After printing the top edge, startRow increases to 2, which is greater than endRow, which is 1.

Cell-by-Cell Spiral Movement

In this approach, we will do exactly what happens when moving spirally in a 2D array. This means we run a single for loop for m * n times, where m and n are the numbers of rows and columns. In each iteration, we prepare for printing the next spiral cell's indices.

For this, we declare two variables row = 0 and col = 0, and then:

  • First, increase col one by one up to endCol.
  • Then, increase row up to endRow.
  • Decrease col up to startCol.
  • Finally, decrease row up to startRow + 1.

After completing one spiral round, we move to the next spiral round by changing variables as follows: col++, startRow++, startCol++, endRow--, and endCol--.

The big question is when we will increase row or col and when we will decrease it. If we think carefully, we see that when moving on the top edge of a spiral round, row == startRow. When on the right edge, col == endCol. This means we can increment col at first until row == startRow && col < endCol.

Here, we do not use col <= endCol because we are preparing for the next cell, not for the current cell. This means when col is endCol - 1, it already increases to col == endCol in the previous iteration and has already been printed.

In the current iteration, the condition row == startRow && col < endCol fails, and we move to the next condition: col == endCol && row < endRow for the right edge, and we increment row. This is like printing the current spiral cell in the current iteration while also preparing for the next.

Now, for the rest of the conditions for decreasing row and col and preparing for the next inner spiral, you can see the complete code of printing using this approach below.

public static void printSpiralCellsWise(int[][] matrix){
    int startRow = 0, endRow = matrix.length-1;
    int startCol = 0, endCol = matrix[0].length -1;
    int row=0, col=0;
    for(int k=0;k<matrix.length*matrix[0].length;k++){
        System.out.print(matrix[row][col] + "  ");

        if (row == startRow && col < endCol) col++; // Move right
        else if (col == endCol && row < endRow) row++; // Move down
        else if (row == endRow && col > startCol) col--; // Move left
        else if (col == startCol && row > startRow + 1) row--; // Move up
        else {
            // Prepare for the next inner spiral
            col++;
            startRow++;
            startCol++;
            endRow--;
            endCol--;
        }
    }
}

The conditions used above come from optimizing the conditions below in two iterations.

// First time conditions
public static void printSpiralCellsWise(int[][] matrix){
    int startRow = 0, endRow = matrix.length-1;
    int startCol = 0, endCol = matrix[0].length -1;
    int direction=0;
    int row=0, col=0;
    for(int k=0;k<matrix.length*matrix[0].length;k++){
        System.out.print(matrix[row][col] + "  ");
        if(direction==0){
            if (col<endCol) col++;
            else{
                direction = 1;
                row++;
            }
        }else if (direction==1) {
            if(row<endRow) row++;
            else {
                direction = 2;
                col--;
            }
        }else if (direction==2) {
            if(col>startCol) col--;
            else {
                direction = 3;
                row--;
            }
        }else if (direction==3) {
            if(row>startRow+1) row--;
            else {
                direction = 0;
                col++;
                startRow++; startCol++;
                endRow--; endCol--;
            }
        }
    }
}

// second time conditions
public static void printSpiralCellsWise(int[][] matrix){
    int startRow = 0, endRow = matrix.length-1;
    int startCol = 0, endCol = matrix[0].length -1;
    int row=0, col=0;
    for(int k=0;k<matrix.length*matrix[0].length;k++){
        System.out.print(matrix[row][col] + "  ");
        if(row==startRow){
            if (col<endCol) col++; else row++; 
        }else if (col==endCol) {
            if(row<endRow) row++; else col--;
        }else if (row==endRow) {
            if(col>startCol) col--; else row--;
        }else if (col==startCol) {
            if(row>startRow+1) row--;
            else {
                col++;
                startRow++; startCol++;
                endRow--; endCol--;
            }
        }
    }
}

What do you think? Which approach is more efficient in terms of both time and space? Of course, the time complexity is the same, O(m*n), in both approaches, but readability has improved in the second approach by removing extra loops.

According to my understanding, the second approach is more efficient in terms of space. This is because, in the second approach, only 6 variables are created irrespective of the number of cells. However, in the first approach, the variable count is 4 fixed variables + 4*r more variables, where r is the number of spiral rounds possible.

I know for loop variables are local and discarded after each while iteration, but constantly creating and discarding variables in each while iteration might have some impact. What do you think? Share your thoughts in the comments.

This is a complete step-by-step guide and something that I have learned while solving this problem. I hope you enjoy reading it and find it informative, helpful, and enjoyable. Thanks for reading, and happy coding!

Published on Jan 25, 2025
Comments (undefined)

Read More