1. 재그드 배열은 2차원 배열과 다릅니다
드디어 많은 사람이 “재그드 배열”이라고 부르는 주제에 도달했습니다 — 영어로는 jagged arrays입니다. 2차원 배열과 달리, 재그드 배열은 길이가 서로 다른 행을 저장할 수 있습니다. 마치 각 건물마다 아파트 수가 다른 건물 단지와 같습니다 — 어떤 건물은 5가구, 다른 건물은 20가구, 또 다른 건물은 단 한 가구만 있는 것처럼요.
재그드 배열은 각 요소가 배열인 배열이며, 내부 배열(‘하위 배열’이라고도 함)의 길이가 서로 다를 수 있습니다.
핵심 차이점:
- 2차원 배열에서는 각 “행”(그리고 각 “열”)의 요소 개수가 동일합니다. 예: int[][] grid = new int[3][5]; — 항상 3개의 행, 각 행에 5개의 요소가 있습니다.
- 재그드 배열에서는 각 행의 길이가 제각각일 수 있습니다! 예: int[][] jagged = new int[3][]; — 그런 다음 각 행(하위 배열)을 필요에 맞게 개별적으로 초기화합니다.
시각적으로 보면 다음과 같습니다:
2차원 배열 (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘
재그드 배열 (길이가 서로 다름):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘
2. 재그드 배열 선언과 초기화 문법
재그드 배열 선언은 이전 타입들을 선언하는 것만큼 어렵지 않습니다! 대괄호가 두 개라고 겁낼 필요는 없습니다:
int[][] jaggedArray = new int[3][];
이는 3개의 요소를 가진 배열이 있고, 각 요소가 int 배열이라는 뜻입니다. 하지만 지금은 내부 배열이 아직 생성되지 않았습니다! 더 잘 이해하기 위해 자세히 살펴봅시다.
재그드 배열 단계별 초기화
1단계 — 기본(외부) 배열 생성:
int[][] jaggedArray = new int[3][];
이제 ‘행’이 3개 있지만, 현재는 모두 null입니다.
2단계 — 내부 배열(하위 배열) 생성 및 설정:
예를 들어 첫 번째 행은 길이 2, 두 번째는 4, 세 번째는 3으로 합시다:
jaggedArray[0] = new int[2]; // 첫 번째 행에 2개의 요소
jaggedArray[1] = new int[4]; // 두 번째 행에 4개의 요소
jaggedArray[2] = new int[3]; // 세 번째 행에 3개의 요소
3단계 — 값 채우기:
내부 배열은 일반 배열입니다! 예를 들면:
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
jaggedArray[1][3] = 6;
jaggedArray[2][0] = 7;
jaggedArray[2][1] = 8;
jaggedArray[2][2] = 9;
재그드 배열을 간단히 초기화하기
값을 미리 알고 있다면 재그드 배열을 한 번에 만들고 채울 수 있습니다:
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7, 8, 9 }
};
또는 내부 배열의 타입을 생략해 더 간단히:
int[][] jaggedArray =
{
{ 1, 2 },
{ 3, 4, 5, 6 },
{ 7, 8, 9 }
};
3. 재그드 배열 순회와 활용
재그드 배열을 순회하는 것은 2차원 배열과 비슷하지만, 이제 바깥 루프는 행을, 안쪽 루프는 각 행의 요소(길이가 서로 다를 수 있음)를 순회합니다:
for (int i = 0; i < jaggedArray.length; i++)
{
System.out.println("행 " + i + ":");
for (int j = 0; j < jaggedArray[i].length; j++)
{
System.out.print(jaggedArray[i][j] + " ");
}
System.out.println();
}
화면 출력 결과:
행 0:
1 2
행 1:
3 4 5 6
행 2:
7 8 9
for-each를 사용하면 인덱스를 신경 쓰지 않아도 됩니다:
for (int[] row : jaggedArray)
{
for (int value : row)
{
System.out.print(value + " ");
}
System.out.println();
}
4. 재그드 배열의 전형적인 사용 사례
언제 재그드 배열이 2차원 배열보다 유용할까요?
- 각 사용자마다 서로 다른 개수의 데이터를 저장할 때: 과목별 점수, 구매 이력, 댓글 등.
- 데이터가 삼각형/계단형 구조일 때(예: 피라미드 출력, 파스칼의 삼각형 등).
- 메모리를 절약하고 싶을 때: 2차원 배열은 모든 행의 길이가 고정이지만, 재그드 배열은 필요한 만큼만 요소를 둡니다.
실전 예: 학생 성적 매니저
예를 들어 학생이 셋 있고, 수학 과제에 대한 점수가 다음과 같다고 합시다:
| 학생 | 점수 |
|---|---|
| 0 | 5, 4 |
| 1 | 3, 4, 4 |
| 2 | 5 |
이러한 배열을 선언해 봅시다:
int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 }; // 첫 번째 학생 — 점수 2개
studentMarks[1] = new int[] { 3, 4, 4 }; // 두 번째 학생 — 점수 3개
studentMarks[2] = new int[] { 5 }; // 세 번째 학생 — 점수 1개
각 학생의 점수를 출력해 봅시다:
for (int i = 0; i < studentMarks.length; i++)
{
System.out.print("학생 " + i + ": ");
for (int j = 0; j < studentMarks[i].length; j++)
{
System.out.print(studentMarks[i][j] + " ");
}
System.out.println();
}
다른 타입과 함께 사용하는 재그드 배열
문자열, 더 깊은 배열의 배열, 심지어 여러분이 만든 객체까지 — 무엇이든 재그드 배열이 될 수 있습니다.
예: 문자열 배열
String[][] groups = {
{ "이반", "표트르" },
{ "마리야", "알렉세이", "세르게이" },
{ "바실리사" }
};
5. 3차원 및 다차원 배열
아마 이미 짐작했겠지만, 배열에 관한 또 하나의 흥미로운 사실이 있습니다. 2차원 배열을 만들 수 있다면 3차원 배열도 만들 수 있을까요?
네, 어떤 차원의 배열이든 만들 수 있습니다. 이런 배열을 다차원 배열이라고 부릅니다.
다차원 배열 선언 방법
대괄호로 필요한 차원의 수를 나열하면 됩니다:
int[][][] cube = new int[2][3][4]; // 2 "층", 3행, 4열
cube[0][1][2] = 99;
여기서는 3차원 배열입니다:
- 2 — 첫 번째 좌표의 요소 수,
- 3 — 두 번째 좌표의 요소 수,
- 4 — 세 번째 좌표의 요소 수.
이런 배열은 연속적으로 저장된 하나의 큰 ‘데이터 큐브’입니다.
3차원 배열 순회
요소에 접근할 때는 모든 인덱스를 함께 지정합니다:
for (int i = 0; i < cube.length; i++)
{
for (int j = 0; j < cube[i].length; j++)
{
for (int k = 0; k < cube[i][j].length; k++)
{
System.out.print(cube[i][j][k] + " ");
}
System.out.println();
}
System.out.println("---");
}
- 인덱스는 언제나 Java에서처럼 0부터 시작합니다.
- 전체 요소 수는 2 × 3 × 4 = 24개입니다.
다차원 배열의 실용적 예시
- 2D — 표, 체스판, 이미지.
- 3D — 컴퓨터 그래픽의 ‘큐브’, 과학 계산용 데이터(예: 시공간의 여러 지점에서의 온도).
- 4D 이상 — 흔하진 않지만 고급 수학, 시뮬레이션, 머신러닝 등에서 사용됩니다.
6. 다차원 배열을 다룰 때 흔한 실수
오류 №1: 배열 범위를 벗어남
가장 흔한 오류는 존재하지 않는 요소에 접근하려는 것입니다. 예를 들면:
int[][] arr = new int[2][3];
arr[2][0] = 5; // 오류! 인덱스 2인 행은 없습니다(0과 1만 존재)
arr[0][3] = 7; // 오류! 인덱스 3인 열은 없습니다(0, 1, 2만 존재)
이렇게 접근하면 프로그램은 ArrayIndexOutOfBoundsException을 던집니다. 인덱스가 항상 허용 범위, 즉 0부터 length - 1까지인지 확인하세요.
오류 №2: 재그드 배열에서 초기화되지 않은 행
재그드 배열을 만들고 내부 배열 초기화를 잊으면, 접근 시 NullPointerException이 발생합니다:
int[][] jagged = new int[3][];
jagged[0][0] = 5; // 오류! jagged[0] == null
먼저 내부 배열을 생성해야 합니다: jagged[0] = new int[2];
오류 №3: 배열 길이 사용을 잘못함
matrix.length(행 수)와 matrix[0].length(열 수)를 혼동합니다. 특히 복사, 순회, 열 합계 계산 시 자주 발생합니다.
오류 №4: 모든 행의 길이가 같다고 가정함
재그드 배열에서는 행의 길이가 서로 다를 수 있습니다! matrix[i][j]를 쓸 때는 j < matrix[i].length인지 확인하세요.
오류 №5: 인덱스 순서를 혼동함
종종 행이 먼저, 열이 나중이라는 것을 헷갈립니다: matrix[행][열]. 거꾸로가 아닙니다!
GO TO FULL VERSION