5-3. 다차원 배열

Hyun Jun·2022년 1월 22일
0

자바의 정석

목록 보기
19/52
post-thumbnail
post-custom-banner

다차원 배열

2차원 배열의 선언과 인덱스

선언

선언 방식은 1차원 배열과 같으나, 2차원 배열은 배열의 배열이기 때문에 대괄호[]가 하나 더 붙음.

2차원 배열에는 주로 테이블 형태의 데이터를 담게 됨.

타입[][] 변수명

예시)

int[][] exampleTable = new int[2][3]; // 2행 3열의 2차원 배열 생성

선언만 한 상태에서는 모든 원소가 int 원소의 기본값인 0

 

인덱스

몇번째 행의 몇번째 열에 있는 원소인지 둘 다 표기해야 함

배열이름[행 인덱스][열 인덱스]

예시)

int exampleElement = exampleTable[1][2]; // exampleTable 배열의 1행 2열에 위치한 원소

 

2차원 배열의 초기화

1차원 배열과 마찬가지로 중괄호{}를 써서 생성과 초기화를 동시에 할 수 있음

int[][] arr = new int[][]{{1, 2, 3}, {4, 5, 6}}; // 2행 3열의 2차원 배열 생성
// 또는
int[][] arr = {{1, 2, 3}, {4, 5, 6}}; // new int[][] 생략 가능

2차원 배열의 원소들을 훑을 때 2중 for문을 돌리게 되는데,

for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
        arr[i][j] = 1; // 모든 원소의 값을 1로 초기화
    }
}

이러한 형식은 향상된 for문을 활용해 조금 더 간략하게 표현할 수 있음

for (int[] row : arr) {
    for (int el : row) {
        el = 1;
    }
}

대신 이 방법은 각 원소의 인덱스에 접근할 수 없으므로 특정 원소의 값을 수정하는데에는 적절치 않음.

 

가변 배열

2차원 배열은 결국 배열의 배열이라는 점을 미루어보아, 다차원 배열을 좀 더 유동적이게 만들 수 있음.

다차원 배열의 맨 마지막 차수 길이를 비워놓으면 추가 배열을 생성할 때마다 다른 길이로 만들어 유동성을 줄 수 있는데 이를 가변 배열이라고 함.

 

예시) 3행짜리 2차원 가변 배열

int[][] flexibleArr = new int[3][]; // 두번째 차수의 길이는 일부러 비워둠
flexibleArr[0] = new int[3];
flexibleArr[1] = new int[1];
flexibleArr[2] = new int[2];

위 예시를 테이블로 나타내보면

[0][0][0][1][0][2]
[1][0]
[2][0][2][1]

 

가변 배열도 중괄호{}를 사용해 간편하게 초기화 할 수 있음

int[][] numbers = {
    {1, 7, 4},
    {5},
    {2, 6}
};

 

다차원 배열의 활용

교재에 제시된 예제로 실습

1. 행렬 내의 특정 위치 마킹

교재에 나온 배 찾기 게임을 변형한 보물찾기 게임. (gameBoard 상에서 0은 꽝, 1은 보물)

public class MultiArrayExample1 {
    public static void main(String[] args) {
        byte[][] gameBoard = {
                {0, 1, 0, 0, 1},
                {1, 0, 1, 1, 0},
                {1, 1, 0, 1, 1},
                {0, 1, 0, 1, 0},
                {1, 0, 0, 0, 1},
        }; // 보물과 꽝 위치가 표시된 정답지 2차원 배열
        final int SIZE = gameBoard.length + 1;
        char[][] guideBoard = new char[SIZE][SIZE]; // 유저의 입력을 받았을 때 O, X를 마킹해줄 2차원 배열

        for (int i = 1; i < SIZE; i++) {
            guideBoard[0][i] = guideBoard[i][0] = (char)(i + '0'); // guideBoard의 첫 행과 첫 열은 좌표를 알아보기 쉽게 행 넘버, 열 넘버 표시
        }

        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.printf("1 ~ %d 사이의 숫자로 이루어진 좌표를 입력하세요. (종료는 exit 입력): ", (SIZE - 1));
            String userInput = scanner.nextLine();

            int x = userInput.charAt(0) - '0'; // 문자를 숫자로 바꾸기 위해 '0'(ASCII 48)을 빼줌
            int y = userInput.charAt(1) - '0';
            boolean outOfRange = x <= 0 || x > SIZE || y <= 0 || y > SIZE; // 입력받을 x와 y 좌표의 범위 이탈 조건

            if (userInput.equals("exit")) {
                break;
            }

            if (!userInput.equals("exit") && (userInput.length() != 2 || outOfRange)) {
                System.out.println("잘못된 입력입니다. 다시 입력해주세요!");
                continue; // while문 맨 처음으로 이동
            }

            guideBoard[x][y] = gameBoard[x-1][y-1] == 1 ? 'O' : 'X'; // 입력한 자리에 보물이 있다면 O, 꽝이면 X 마킹

            for (int i = 0; i < SIZE; i++) {
                System.out.println(guideBoard[i]); // 마킹이 반영된 2차원 배열을 콘솔에 출력하여 표시
            }
        }
    }
}

 

2. 행렬의 곱셈

2차원 배열을 하나의 행렬이라고 생각하고 행렬의 곱셈처럼 곱 연산을 할 수 있음.

교재 풀이에서는 아래처럼 3중 for문을 썼지만, 곱하기 전에 먼저 2번째 피연산 행렬을 뒤집어놓으면 2중 for문으로 해결 가능

public class MultiArrayExample2 {
    public static void main(String[] args) {
        int[][] m1 = {
                {5, 1, 4},
                {2, 6, 3}
        }; // 3x2 행렬
        int[][] m2 = {
                {3, 6},
                {2, 1},
                {4, 5}
        }; // 2x3 행렬
        final int ROW = m1.length; // 행의 개수 (2)
        final int COLUMN = m2[0].length; // 열의 개수 (2)
        int[][] m3 = new int[ROW][COLUMN]; // 곱의 결과로 나온 배열 m3

        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COLUMN; j++) {
                for (int k = 0; k < m2.length; k++) {
                    m3[i][j] += m1[i][k] * m2[k][j]; // m3의 원소에 m1, m2 원소들의 곱이 더해지게 함
                }
            }
        } // 이러한 3중첩 for문은 연산 효율이 기하급수적으로 떨어지므로 되도록 지양...

        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COLUMN; j++) {
                System.out.printf("%d ", m3[i][j]); // 한 행 안에서 모든 원소 출력
            }
            System.out.println(); // 한 행이 마무리되면 줄 바꿈
        }
    }
}

 

3. 행과 열 뒤집기

교재에는 없으나 알아두면 유용할 것 같아서 함.

public class IntChar {
    public static void main(String[] args) {
        int[][] m1 = {
                {9, 2, 5, 10},
                {4, 8, 12, 1},
                {11, 7, 6, 3},
        }; // 4x3 행렬
        final int ROW = m1.length;
        final int COLUMN = m1[0].length;
        int[][] m2 = new int[COLUMN][ROW]; // 행과 열을 뒤집은 결과를 담을 배열

        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COLUMN; j++) {
                m2[j][i] = m1[i][j]; // m1과 m2는 같은 원소에 대해 행과 열의 좌표가 반대임
            }
        }

        for (int i = 0; i < COLUMN; i++) {
            for (int j = 0; j < ROW; j++) {
                System.out.printf("%d ", m2[i][j]); // m2 각 행의 원소 출력
            }
            System.out.println(); // 한 행이 끝나면 줄바꿈
        }
    }
}
profile
Back-end Engineer 👨‍💻
post-custom-banner

0개의 댓글