Array(배열)
자료구조로써 Array(배열)
같은 Type의 변수들을 인접한 Memory 위치에 있는 Data를 모아놓은 집합
- 필요성과 특징
- element가 일렬로 나열되어 있는 '선형 자료구조' 이다.
- 중복을 허용하고, 순서가 있다.
- 같은 종류의 Data를 효율적으로 관리하기 위해서 사용한다.
- 이를 통해, 첫 Data의 위치에서 상대적인 위치(index)로 Data를 접근하여 빠른 접근이 가능하다.
- 다만 이러한 특징으로 Data의 추가 및 삭제가 어려워, 미리 Array의 최대 길이를 지정해야 한다는 단점이 있다.
Java에서 Array
기본 문법
Java는 기본 문법으로 Array를 지원한다.
int [] x = {length};
int [] ex1 = {1,2,3,4,5};
System.out.println(ex1[0]); // 1
기본 Array는 객체를 생성할 때 Array의 크기를 선언하도록 되어있다.
java.util.Arrays
Java는 Array를 보다 쉽게 다루기 위한 Class를 제공한다.
import java.util.Arrays;
System.out.println(Arrays.toString(ex1));
- 기본 문법에서 선언한 int형 Array를 String으로 변환한다.
List와 ArrayList
- java.util의 Interface List
List <Integer> list1 = new ArrayList<Integer>();
List는 Interface로 모든 method가 추상 메서드인 경우를 의미한다.
List라는 Interface 안에 ArrayList 클래스가 있다. (도형 - 정사각형의 관계라고 비유할 수 있다.)
List로 선언된 변수는 필요에 따라 다음과 같이 다른 List의 클래스를 쓸 수 있는 구현상의 유연성을 제공한다.
List <Integer> list1 = new ArrayList<Integer>();
list1 = new LinkedList<Integer>();
- java.util.ArrayList
ArrayList <Integer> = new ArrayList<Integer>();
ArrayList는 Interface인 List와 달리 Class이다. ArrayList class로 구현한 Array는 data를 추가하는데로 size가 동적으로 늘어난다. 이 때, 배열 방이 다 차게되면(확장한 공간을 모두 사용) Array의 크기를 두 배로 늘리게 된다. 두 배로 늘린 Array에 기존 배열에 있었던 data를 모두 복사하게 되는데 이를 Doubling(더블링) 이라 한다.
코드를 통해 살펴보자.
public class Main {
public static class ArrayList {
private Object[] data;
private int size; // array의 크기
private int index; // 다음 data를 추가할 위치를 기억하고 있는 index
public ArrayList() {
this.data = new Object[this.size];
this.size = 1;
this.index = 0; //
}
// data 추가
public void add(Object object) {
if (this.index == this.size - 1) { // 배열방이 모두 찼다면
doubling(); // doubling을 실행
}
data[this.index] = object; // 공간이 있다면, 배열방 맨 끝에 data를 추가
this.index++; // data 추가로 index 1 증가
}
}
// doubling 과정
private void doubling() {
this.size = this.size * 2; // 현 배열방을 2배로 늘림
Object[] newData = new Object[this.size];
for (int i = 0; i < data.length; i++) {
newData[i] = data[i]; // doubling을 통해 배열방을 현 data로 할당
}
this.data = newData;
}
public Object get(int i) throws Exception {
if (i > this.index - 1) {
throw new Exception("ArrayIndexOutOfBound");
} else if (i < 0) {
throw new Exception("Negative Value");
}
return this.data[i];
}
public void remove(int i) throws Exception {
if (i > this.index - 1) {
throw new Exception("ArrayIndexOutOfBound");
} else if (i < 0) {
throw new Exception("Negative Value");
}
for (int x = i; x < this.data.length - 1; x++) {
data[x] = data[x + 1]; // 삭제할 data 기준으로 한 칸씩 앞으로
}
this.index--; // index를 1 감소
}
}
// main 메서드에서 실행
ArrayList al = new ArrayList();
al.add("0");
al.add("1");
al.add("2");
al.add("3");
al.add("4");
al.add("5");
al.add("6");
System.out.println(al.get(5)); // 5
al.remove(5);
System.out.println(al.get(5)); // 6
Array의 시간 복잡도
- 접근
접근은 Array 내에서 n번 째 index에 해당하는 값을 찾아내는 연산이다. Array의 접근은 O(1) 의 시간 복잡도를 갖는다. 찾고자 하는 값이 몇 번째 index에 있는지 알고 있따면 빠른 검색 속도를 갖는다. Array의 첫 번째 변수에는 시작 주소값이 저장되고, A[n]의 값을 찾아가기 위해 시작주소값에서 단순 사칙연산이 수행되기 때문이다.
- 탐색
Array의 탐색은 순차 탐색이다. index를 알지 못할 때 원하는 값을 찾기 위해 Array를 배열을 모두 확인해야 한다.
위에서 A[3]의 값을 찾기위해서는 A[0]부터 순서대로 A[3]까지 순서대로 탐색한다. 즉 O(n) 의 시간 복잡도를 가진다.
- 삽입 및 삭제
Array에 빈 공간이 있다는 것을 전제로, A[6]에 5라는 값을 삽입하거나 삭제하고 싶을 때, 해당 index를 알고 있다면 O(1)의 시간 복잡도를 가지지만, 해당 index를 탐색해야 한다면 탐색의 시간복잡도인 O(n) 에 해당한다.
참고자료
- https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Array.html
- https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html
- https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html
- https://www.baeldung.com/java-collections-complexity
- https://www.youtube.com/watch?v=I4_uFyjWZn4&t=60s&ab_channel=%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD