이 글에서는 자바(Java)를 이용해 행렬(matrix)의 요소를 회전하는 방법을 단계별로 살펴봅니다. 행렬은 데이터를 행(row)과 열(column) 형태로 표현한 2차원 배열이며, 행렬 회전이란 각 요소를 테두리를 따라 오른쪽 또는 왼쪽으로 한 칸씩 밀어내는 연산을 의미합니다.
행렬 회전의 이해
예를 들어 아래와 같은 4×4 행렬이 입력으로 주어졌다고 가정해 보겠습니다.
입력 행렬: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
이 행렬을 한 번 회전하면 모든 요소가 시계 방향으로 한 칸씩 이동하여 다음과 같은 결과가 됩니다.
1회 회전 후 행렬: 5 1 2 3 9 10 6 4 13 11 7 8 14 15 16 12
알고리즘
Step 1 - 시작합니다. Step 2 - 정수형 행렬 input_matrix를 선언하고, row, column, previous, current 네 개의 정수 변수를 준비합니다. Step 3 - 행렬의 값을 정의합니다. Step 4 - while 루프와 여러 개의 for 루프를 사용해 행렬의 각 요소를 순회하며, 각 요소를 오른쪽으로 한 칸씩 이동한 결과를 저장합니다. Step 5 - 결과를 출력합니다. Step 6 - 종료합니다.
동작 원리
이 알고리즘은 행렬의 가장 바깥쪽 테두리부터 나선형(spiral)으로 안쪽으로 들어가며 요소를 이동시킵니다. row와 column은 현재 처리 중인 테두리의 시작 위치를, m과 n은 남은 영역의 마지막 행과 열을 가리킵니다. 위쪽 행 → 오른쪽 열 → 아래쪽 행 → 왼쪽 열 순서로 값을 한 칸씩 교체하면, 전체 요소가 시계 방향으로 한 칸씩 회전한 효과를 얻을 수 있습니다. 시간 복잡도는 행렬의 모든 요소를 한 번씩 방문하므로 O(m×n)입니다.
예제 1: main 메서드에서 직접 처리하기
첫 번째 예제에서는 행렬을 main 메서드 안에 직접 정의하고, 별도의 메서드 호출 없이 회전 로직을 바로 수행한 뒤 결과를 콘솔에 출력합니다.
public class RotateMatrix {
static int Rows = 4;
static int Columns = 4;
public static void main(String[] args) {
int input_matrix[][] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
System.out.println("정의된 입력 행렬:");
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Columns; j++)
System.out.print( input_matrix[i][j] + " ");
System.out.print("
");
}
int m = Rows, n = Columns;
int row = 0, column = 0;
int previous, current;
while (row < m && column < n) {
if (row + 1 == m || column + 1 == n)
break;
previous = input_matrix[row + 1][column];
for (int i = column; i < n; i++) {
current = input_matrix[row][i];
input_matrix[row][i] = previous;
previous = current;
}
row++;
for (int i = row; i < m; i++) {
current = input_matrix[i][n-1];
input_matrix[i][n-1] = previous;
previous = current;
}
n--;
if (row < m) {
for (int i = n-1; i >= column; i--) {
current = input_matrix[m-1][i];
input_matrix[m-1][i] = previous;
previous = current;
}
}
m--;
if (column < n) {
for (int i = m-1; i >= row; i--) {
current = input_matrix[i][column];
input_matrix[i][column] = previous;
previous = current;
}
}
column++;
}
System.out.println("
1회 회전 후 행렬:");
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Columns; j++)
System.out.print( input_matrix[i][j] + " ");
System.out.print("
");
}
}
}실행 결과
정의된 입력 행렬: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1회 회전 후 행렬: 5 1 2 3 9 10 6 4 13 11 7 8 14 15 16 12
예제 2: 별도 메서드로 분리하기
두 번째 예제에서는 회전 로직을 Rotate_matrix라는 별도의 정적(static) 메서드로 분리했습니다. 행렬과 그 크기를 인자로 전달하면 메서드가 회전을 수행하고 결과를 출력합니다. 로직이 함수 하나에 캡슐화되므로 코드의 재사용성과 가독성이 훨씬 좋아집니다.
public class RotateMatrix {
static int Rows = 4;
static int Columns = 4;
static void Rotate_matrix(int m,
int n, int matrix[][]) {
int row = 0, column = 0;
int previous, current;
while (row < m && column < n) {
if (row + 1 == m || column + 1 == n)
break;
previous = matrix[row + 1][column];
for (int i = column; i < n; i++) {
current = matrix[row][i];
matrix[row][i] = previous;
previous = current;
}
row++;
for (int i = row; i < m; i++) {
current = matrix[i][n-1];
matrix[i][n-1] = previous;
previous = current;
}
n--;
if (row < m) {
for (int i = n-1; i >= column; i--) {
current = matrix[m-1][i];
matrix[m-1][i] = previous;
previous = current;
}
}
m--;
if (column < n) {
for (int i = m-1; i >= row; i--) {
current = matrix[i][column];
matrix[i][column] = previous;
previous = current;
}
}
column++;
}
System.out.println("
1회 회전 후 행렬:");
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Columns; j++)
System.out.print( matrix[i][j] + " ");
System.out.print("
");
}
}
public static void main(String[] args) {
int input_matrix[][] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
System.out.println("정의된 입력 행렬:");
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Columns; j++)
System.out.print( input_matrix[i][j] + " ");
System.out.print("
");
}
Rotate_matrix(Rows, Columns, input_matrix);
}
}실행 결과
정의된 입력 행렬: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1회 회전 후 행렬: 5 1 2 3 9 10 6 4 13 11 7 8 14 15 16 12
마무리
지금까지 자바에서 행렬의 요소를 시계 방향으로 한 칸씩 회전시키는 두 가지 방식을 살펴보았습니다. 첫 번째 방식은 간단하게 결과를 확인할 때 유용하고, 두 번째 방식처럼 로직을 별도 메서드로 분리하면 다양한 크기의 행렬에 재사용할 수 있어 실무에서 더 권장됩니다. 이 알고리즘은 나선형 배열 출력, 이미지 회전 등 다양한 응용 문제의 기초가 되므로 직접 코드를 작성하며 동작 원리를 익혀 보시기 바랍니다.