- 배열은 동일한 타입의 여러 개의 데이터를 하나의 이름으로 그룹화하여 관리할 수 있는 구조이다.
- 배열의 각 요소는 인덱스라는 고유한 번호로 식별되며, 이 인덱스를 통해 배열의 데이터에 접근할 수 있다.
- 이런 방식은 반복문과 같은 제어 구조와 결합할 때 유용하다
배열이란?
배열은 동일한 데이터 타입의 여러 값을 담을 수 있는 자료 구조이다. 배열은 기본 데이터 타입(int, char 등) 또는 객체(문자열, 사용자 정의 객체 등)의 참조를 저장할 수 있다.
배열의 특징
- 동일한 타입의 데이터 저장 : 배열은 한 번 생성하면 그 타입 외의 다른 타입의 데이터를 저장할 수 없다.
- 고정된 크기 : 배열은 생성 시에 지정한 크기를 변경할 수 없다. 따라서 한 번 생성된 배열에 더 많은 데이터를 저장하려면 새로운 배열을 만들어야되고, 이는 메모리와 처리 시간을 추가로 필요로 한다.
- 인덱스를 통한 빠른 접근 : 배열의 요소에는 고유한 인덱스가 있어 배열의 데이터에 따르게 접근할 수 있다.
배열을 선언하려면 데이터 타입 뒤에 대괄호([])를 붙인다.
int[] Array;
배열에 값을 할당하려면 'new' 키워드를 사용하여 배열을 초기화하고 값을 할당할 수 있습니다.
int[] Array = new int[5];
배열의 요소에 접근하려면 인덱스를 사용한다. 인덱스는 0부터 시작하고, 배열의 길이보다 1이 작다
Array[0] = 1; // 배열의 첫 번째 위치에 1을 할당합니다.
int firstElement = Array[0]; // 첫 번째 위치의 값을 가져옵니다.
배열의 장점
1. 인덱스를 통한 빠른 접근 : 인덱스를 이용하여 빠르게 접근할 수 있다. O(1)의 시간 복잡도를 가진다.
2. 메모리 효율성 : 배열은 메모리를 연속적으로 사용하기 때문에 메모리 효율성이 높다. 그리고 고정된 크기를 가지고 있어서 메모리를 절약할 수 있다.
배열의 단점 및 해결방법
1. 고정된 크기 :
배열의 크기를 선언 시에 고정되며, 크기를 변경할 수 없다. 그래서 배열이 가득 찬 상태에서 새로운 요소를 추가하거나 배열에 남은 공간이 많은 경우에는 메모리가 낭비될 수 있다.
해결방법 :
동적 배열을 사용하면 문제를 해결할 수 있다. 대표적인 예로는 ArrayList가 있다.
2. 데이터의 삽입과 삭제 :
배열에서 요소를 삽입하거나 삭제하는 것은 비 효율적이다. 왜냐하면 요소를 삽입하거나 삭제하려면 모든 요소를 이동해야 하기 때문이다.
이렇게 하면 O(n)의 시간 복잡도를 가진다.
해결방법 :
연결 리스트(linked list)를 사용하면 해결할 수 있다. 연결 리스트는 요소의 삽입과 삭제를 O(1)의 시간 복잡도로 처리할 수 있다.
3. 타입 제한 :
배열은 동일한 타입의 요소만 저장할 수 있다. 이로 인해서 다양한 타입의 데이터를 저장하는데 제한적일 수 있다.
해결방법 :
객체를 사용하여 다양한 타입의 데이터를 저장할 수 있다. 또는 제너릭을 사용하는 컬렉션 프레임워크(ArrayList, LinkedList 등)을 사용하면 여러 타입의 데이터를 한 곳에 저장할 수 있다.
배열 관련 메서드 정리
toString - 배열의 모든 요소를 문자열로 변환하여 반환
int[] array = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(array)); // [1, 2, 3, 4, 5]
sort - 배열의 모든 요소를 오름차순으로 정렬
int[] array = {5, 3, 9, 1, 6};
Arrays.sort(array);
System.out.println(Arrays.toString(array)); // [1, 3, 5, 6, 9]
copyOf - 원본 배열의 복사본을 생성하여 반환
int[] original = {1, 2, 3, 4, 5};
int[] copied = Arrays.copyOf(original, 3);
System.out.println(Arrays.toString(copied)); // [1, 2, 3]
equals - 두 배열이 동일한지 확인
int[] array1 = {1, 2, 3, 4, 5};
int[] array2 = {1, 2, 3, 4, 5};
System.out.println(Arrays.equals(array1, array2)); // true
fill - 주어진 값으로 배열의 모든 요소를 채운다
int[] array = new int[5];
Arrays.fill(array, 1);
System.out.println(Arrays.toString(array)); // [1, 1, 1, 1, 1]
binarySearch(array, key) - 이진 검색 알고리즘을 사용하여 배열에서 특정 요소를 찾는다. (배열은 검색 전에 정렬되어있어야한다)
int[] array = {2, 5, 7, 9, 12};
Arrays.sort(array);
int index = Arrays.binarySearch(array, 7);
System.out.println(index); // 2
deepEquals(array1 , array2) - 다차원 배열인 경우 두 배열이 동일한지 검사한다
int[][] array1 = {{1, 2, 3}, {4, 5, 6}};
int[][] array2 = {{1, 2, 3}, {4, 5, 6}};
System.out.println(Arrays.deepEquals(array1, array2)); // true
deepToString(array) - 다차원 배열의 요소를 포함한 문자열 표현을 반환한다
int[][] array = {{1, 2, 3}, {4, 5, 6}};
System.out.println(Arrays.deepToString(array)); // [[1, 2, 3], [4, 5, 6]]
asList(array) - 배열을 ArrayList로 변환한다.단 변환된 리스트의 크기는 고정되어있다(추가 삭제 불가능)
String[] array = {"Apple", "Banana", "Cherry"};
List<String> list = Arrays.asList(array);
System.out.println(list); // [Apple, Banana, Cherry]
hashCode(array) - 배열의 해시코드 값을 반환한다. (해시코드는 객체를 식별하기 위한 정수 값)
int[] array = {1, 2, 3, 4, 5};
int hashCode = Arrays.hashCode(array);
System.out.println(hashCode); // 해시코드 값
stream(array) - 배열을 Stream으로 변환한다.
int[] array = {1, 2, 3, 4, 5};
Arrays.stream(array).forEach(System.out::println);