자바의 정석

Chapter 05 배열 - 배열

dev-byul 2022. 2. 19. 21:28

배열이란 ?

  • 배열은 같은 타입의 여러 변수를 하나의 묶음으로 다루는 것

여기서 keyPoint 같은 타입이어야 한다는 것입니다. 서로 다른 타입의 변수들로 구성된 배열은 만들 수 없으며, 다른 타입의 값을 대입할 수 없습니다.

배열은 왜 사용하는가 ?

5개의 점수 데이터를 받아서 저장을 해야 하는 경우 배열을 사용하지 않을 경우 다음과 같이 작성합니다.

int score1, score2, score3, score4, score5;

하지만 배열을 사용하게 될 경우 다음과 같이 간단히 처리 할 수 있습니다.

int[] score = new int[5];

배열의 선언과 생성

배열 선언

저자의 경우 대괄호를 타입에 붙이는 쪽을 선호한다. 대괄호가 변수이름의 일부라기보다는 타입의 일부라고 보기 때문이다. P.183

선언 방식은 2가지의 방법이 있습니다. 타입[] 변수이름;타입 변수이름[]; 형식 처럼 대괄호[ ] 를 붙이는 방식으로 선언할 수 있습니다. 대괄호[ ] 는 타입 뒤 혹은 변수 이름뒤에 붙여도 무방합니다.

선언방법 선언예
타입[] 변수이름; int[] score;
타입 변수이름[]; int score[];

배열 생성

배열을 생성하기 위해서는 연산자 new 와 함께 배열의 타입과 길이를 지정해 주어야 합니다.

여기서 주의 할 점이 있습니다.

  1. 배열을 선언 하는 것은 단지 생성된 배열을 다루기 위한 참조변수를 위한 공간 을 만드는 것
  1. 배열을 생성해야만 비로소 값을 저장할 수 있는 공간을 만드는 것

배열을 생성하는 방법은 2가지가 있습니다.

  1. 배열을 선언하고 생성하는 방식 

 

  1. int[] score; // 배열을 선언 (배열을 다루기 위한 참조변수 선언) score = new int[5] // 배열을 생성 (실제 저장공간을 생성)
  1. 배열을 선언과 생성을 동시에 하는 방식
    int[] score = new int[5]; // 배열 생성 및 선언

배열의 길이와 인덱스

배열의 인덱스

생성된 배열의 각 저장공간을 배열의 요소(element) 라고 합니다. 배열이름[index] 의 형식으로 배열의 요소에 접근합니다.

  • index 는 배열의 요소마다 붙여진 일련번호로 각 요소를 구별하는데 사용됩니다. 여기서 주의사항은 index 값은 1 이 아닌 0부터 시작합니다.
    int[] score = new int[5];
    for(int i = 0; i < 5; i++)
    	score[i] = i * 10;
    System.out.println(Arrays.toString(score)); // [10,20,30,40,50]
  • 배열에 접근 할때 주의해야 할 점은 배열의 크기 이상의 인덱스 값으로 접근을 하면 안된다는 것입니다. 크기 이상의 인덱스 값으로 접근 할 경우 ArrayIndexOutOfBoundsException 에러가 발생합니다.
    int[] score = new int[5];
    score[5] = 100; // Error 발생
    // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
  • 배열의 크기 이상의 인덱스 값으로 접근 할 경우 컴파일 시에는 아무런 문제가 발생하지 않지만, 실행 시에는 ArrayIndexOutOfBoundsException 에러가 발생합니다.

배열의 길이

길이가 0인 배열이 필요한 상황이 있고 나름 유용하다. P.187

배열의 길이는 배열의 요소의 개수, 즉 값을 저장할 수 있는 공간의 개수 를 의미합니다.

  • 배열의 길이는 양의 정수여야 하고, int 타입으로 작성해야 합니다.
  • 배열의 길이가 0인 배열도 생성이 가능합니다.

배열이름.length

자바에서는 JVM(Java Virtual Machine)이 모든 배열의 길이를 별도로 관리하며, 배열이름.length를 통해서 배열의 길이에 대한 정보를 얻을 수 있습니다.

int[] score = new int[5]; 
int score_length = score.length; // 5
  • 배열은 한번 생성하면 배열의 길이를 변경이 불가능 합니다.
  • 따라서 배열의 길이는 상수 값입니다.
  • 공간이 부족한 경우 더 큰 길이의 새로운 배열을 생성한 다음 기존의 배열에 저장된 값들을 새로운 배열에 복사하면 됩니다.

배열의 초기화

배열은 생성과 동시에 자동적으로 자신의 타입에 해당하는 기본 값으로 초기화됩니다.

배열을 초기화 하는 방법은 2가지가 있습니다.

    1. default 값으로 초기화 
int[] score = new int[5]; System.out.println(Arrays.toString(score)); // [0,0,0,0,0]
  1. 원하는 값으로 초기화
    int[] score = new int[] { 10, 20, 30, 40, 50 };
    System.out.println(Arrays.toString(score)); // [10,20,30,40,50]

 

배열 생성시 new 타입[] 에 대한 주의 사항은 다음과 같습니다.

  • 생략 가능한 경우
    1. 배열 생성과 선언을 같이 하는 경우 생략할 수 있습니다.
      int[] score = { 10, 20, 30, 40, 50 }; // new int[] 를 생략할 수 있다.
  • new 타입[]을 반드시 작성해야 하는 경우
    • 배열 생성과 선언을 따로 할 경우 생략할 수 없습니다.
      int[] score;
      score = new int[] { 10, 20, 30, 40, 50 };
    • 메서드의 매개변수로 작성할 때는 생략할 수 없습니다.
      int zeroIndexReturn(int[] arr) {return arr[0];}
      int result = zeroIndexReturn(new int[] { 10, 20, 30, 40, 50 });

 

배열의 길이가 0인 배열을 생성해보자

  • 괄호 { } 안에 아무것도 넣지 않으면 길이가 0인 배열이 생성됩니다.
int[] score = new int[0];
int[] score = new int[]{};
int[] score = {};

배열의 출력

배열 출력은 index 값을 통해 접근 하거나, Arrays.toString(배열이름) 을 통해 출력 할 수있습니다.

import java.util.Arrays;
//... 생략
int[] score = { 10, 20, 30, 40, 50 };
for(int i = 0; i < score.length; i++) {
	System.out.print(score[i]+", ");
}
System.out.println();
System.out.println(Arrays.toString(score));
/*
10, 20, 30, 40, 50, 
[10, 20, 30, 40, 50]
*/

Arrays.toString 은 java.util.Arrays 가 import 되어 있어야 사용이 가능합니다.


배열의 복사

배열은 한번 생성하면 그 길이를 변경할 수 없기 떄문에 더 많은 저장공간이 필요하다면 보다 큰 배열을 새로 만들고 이전 배열로부터 내용을 복사해야한다고 했다. P.192

배열 복사 방법은 2가지가 있습니다.

  1. for문을 이용해서 배열을 복사 하는 방법
    int[] nums = { 1, 2, 3, 4, 5 };
    int[] tmp = new int[nums.length * 2];
    for (int i = 0; i < nums.length; i++) {
    	tmp[i] = nums[i];
    }
    
    nums = tmp; // 참조변수 nums가 새로운 배열을 가리키게 됩니다.
    System.out.println(Arrays.toString(nums)); // [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
    배열은 참조변수를 통해서만 접근할 수 있기 때문에, 자신을 가리키는 참조변수가 없는 배열은 사용할 수 없습니다. 이렇게 쓸모없게 된 배열은 JVM의 가비지 컬렉터에 의해서 자동적으로 메모리에서 제거됩니다.
  1. System.arraycopy()를 활용한 배열 복사
    int[] nums_1 = { 1, 2, 3, 4, 5 }; // 길이가 5인 배열
    int[] nums_2 = { 6, 7, 8, 9 }; // 길이가 4인 배열
    int[] result = new int[nums_1.length + nums_2.length]; // 길이가 5 + 4인 배열
    
    System.arraycopy(nums_1, 0, result, 0, nums_1.length);
    System.arraycopy(nums_2, 0, result, nums_1.length, nums_2.length);
    System.out.println("result : " + Arrays.toString(result));
    배열의 복사는 for문보다 System.arraycopy()를 사용하는 것이 효율적입니다.
  2. 복사하려는 배열의 위치가 적절하지 못하여 복사하려는 내용보다 여유공간이 부족하면 ArrayIndexOutOfBoundsException에러가 발생합니다.

배열의 활용성

정렬하기(sort) - 버블 정렬

int[] arr = { 1, 7, 4, 2, 1, 7, 8, 5, 5, 8 };

for (int i = 0; i < arr.length - 1; i++) {
	boolean checked = false;
	for (int j = 0; j < arr.length - 1 - i; j++) {
		if (arr[j] > arr[j + 1]) {
			int tmp = arr[j];
			arr[j] = arr[j + 1];
			arr[j + 1] = tmp;
			checked = true;
		}
	}
	if(!checked) break;
}

System.out.println(Arrays.toString(arr)); // [1, 1, 2, 4, 5, 5, 7, 7, 8, 8]
  • 버블정렬 알고리즘의 정렬방법은 간단합니다. 배열의 길이가 n일 때, 배열의 첫 번째부터 n - 1까지의 요소에 대해, 근접한 값과 크기를 비교하여 자리바꿈을 반복하는 것입니다.
  • 만일 크기를 비교해서 변경점이 없을 경우 모든 배열의 정렬이 끈났다는 의미이기 때문에 이를 체크해서 반복문을 종료합니다.

빈도수 체크 하기

int[] arr = { 1, 7, 4, 2, 1, 7, 8, 5, 5, 8 };
int[] count = new int[10];
for (int i = 0; i < arr.length; i++) {
	count[arr[i]] += 1;
}
for (int i = 0; i < count.length; i++) {
	System.out.print(i + " = " + count[i] + " | ");
// 0 = 0 | 1 = 2 | 2 = 1 | 3 = 0 | 4 = 1 | 5 = 2 | 6 = 0 | 7 = 2 | 8 = 2 | 9 = 0 |
}

알고리즘을 풀다 이와 비슷한 문제를 풀었던 기억이 있었습니다. [a-z] 혹은 [0-9] 처럼 일정한 갯수의 경우의 수가 존재 할 때, 사용하면 유용한 방식인 것 같습니다.