우아한테크코스/1주차 프리코스
[Java] 1주차 스터디 - 파이썬 list 자바 Array, ArrayList 에 대해!
행복한라이언
2023. 10. 21. 17:45
728x90
반응형
1. Array
- 연관된 data를 메모리상에 연속적이며 순차적(ordered)으로 미리 할당된 크기(fixed-size)만큼 저장하는 자료구조
- 장점: 조회가 매우 빠름
- 단점: 미리 할당된 크기를 선언해야하므로 메모리 낭비 또는 할당된 사이즈를 넘는 경우 문제 발생
- 시간복잡도
- 조회: O(1)
- 추가: O(1)
- 삽입, 삭제: O(n)
2. Python - list와 Java - ArrayList
1) Python의 list와 Java의 ArrayList 내부 로직 - Dynamic Array
- 거의 동일하므로 [ Java-ArrayList = Python - list ]로 생각하면 세상 쉽다!
- [차이점] Python-list에서는 Object의 주소값이 들어가서 타입 제한 없이 요소가 될 수 있다.
- 내부로직(Dynamic Array): Array의 fixed-size 단점을 보완하기 위한 자료구조이다. 간단하게 설명하면 Java-ArrayList가 동적배열이긴 하나 기본적으로 설정된 크기(default-capacity)가 존재하는데 요소가 추가될 때마 size가 1씩 증가한다. capacity와 size가 같아져 더 이상 공간이 없을 경우 Resize를 한다. Resize에는 여러 방법이 존재하는데 대표적인 방법으로는 Doubling이 존재한다. 메모리를 초과하게 되면 기존 배열의size보다 두배 큰 배열을 선언하고 데이터를 일일이 옮긴다.
- Resize가 발생할 때의 시간복잡도는 어떻게 될까?
- 평균적으로 O(1)의 시간복잡도를 가진다.
- Doubling을 가정하고 길이 N을 2^x 라고 할 때, add를 N번 시행하면 할당 연산이 총 N번, 복사 연산은 2N번 발생 한다
- 1+2+4+8 ... 2^x(N) = 2^(x+1) = N * 2
- N번 시행에 총 3N의 연산 발생. 회당 평균 시간 복잡도는 O(3N/N) = O(3) = O(1)
- 평균적으로 O(1)의 시간복잡도를 가진다.
2) ArrayList의 add 아는 선에서 최대한 뜯어보기!
// ArrayList 내부
private static final int DEFAULT_CAPACITY = 10;
private int size;
// 요소가 추가될 때..
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
return grow(size + 1);
}
//
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// preconditions not checked because of inlining
// assert oldLength >= 0
// assert minGrowth > 0
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}
- prefLength = oldLength + Math.max(minGrowth, prefGrowth)인데 prefGrowth는 'oldCapacity >> 1' 즉, 절반(비트연산)에 해당한다. 따라서 resize된 크기는 prefLength가 반환될 시에 기존 크기의 최대 1.5배만큼 늘어나게 된다.
- 크기가 최대 1.5배가 된 배열이 생성이 되고 elementData의 요소들이 복사된다.
- 그 후 elementData[s] = e로 요소가 추가된다.
- size 를 1 증가시키고 add 종료된다.
3. Array와 ArrayList
- ArrayList 왜 권장할까?
- Python-list를 사용하다가 Java-Array 만나면 굉장히 답답하다. 그 이유는 append, remove, pop, del, clear, index 등의 메서드가 너무~너무 부족하다.
- 컬렉션 ArrayList 만나면 이미 구현해놓은 메서드가 많아져서 사용하기 매우 간편하다.
- 따라서 Array 보다 ArrayList 쓰는 가장 근본적 이유는 메서드가 많아서 쓰기 편해서 그런 것 같다.
- ★메서드 종류(https://happy-ryan.tistory.com/34)★
Array | ArrayList | |
성격 | 정적배열 | 동적배열 |
요소의 개수 | length() | size() |
요소 추가 | 인덱스로 접근해서 추가 | add() |
4. 학습 필요
1) " 배열은 제네릭 사용 불가능, ArrayLis 제네릭 사용 가능"
→ 제네릭이 무엇인가?
728x90
반응형