본문 바로가기

동적 배열의 용량 정책

size와 용량을 분리한 MyArrayList를 만들고 가득 찬 순간 두 배 확장과 원소 복사를 확인합니다.

고정 배열 기반 목록은 남은 칸이 있는 동안 정상처럼 보입니다.

세 번째 게시글 제목이 들어오는 순간 내부 배열 예외가 나오면 호출자는 자료 구조의 정책을 알 수 없습니다.

동적 구현은 요구 크기, 현재 size, 현재 용량을 매 삽입 직전에 비교해 확장 시점을 명확히 만듭니다.


세 번째 add 전 용량 확인 누락

두 칸 배열에 세 번째 제목을 추가합니다.

예외는 values[size++]에서 인덱스 2에 저장하려 할 때 발생합니다.

이 오류를 그대로 노출하면 “목록은 추가할 수 있다”는 추상화가 깨집니다.

lab/FixedCapacityOverflowFailure.java
public final class FixedCapacityOverflowFailure {
    public static void main(String[] args) {
        String[] values = new String[2];
        int size = 0;
        values[size++] = "array";
        values[size++] = "list";
        values[size++] = "growth";
    }
}
관찰 결과
java.lang.ArrayIndexOutOfBoundsException

삽입 전에 필요한 용량인 size + 1을 계산하지 않았습니다.

확장 정책은 새 용량이 필요 용량 이상임을 보장해야 하며, 길이가 0인 배열도 증가할 수 있도록 최소 용량을 정해야 합니다.


필요 용량과 두 배 성장 규칙

  • add는 저장 전에 필요 용량을 계산하고 부족할 때만 배열을 교체합니다.
  • 새 길이는 현재 길이의 두 배와 요구 길이 중 큰 값으로 정해 한 번에 충분히 확보합니다.
  • 아래 DynamicTitleList는 Arrays.copyOf로 기존 배열을 복사합니다. 뒤의 CLI는 System.arraycopy에 size를 전달해 사용 구간을 복사합니다.
  • 확장 한 번은 O(n)이지만 여러 끝 삽입에 나누어 보면 평균 비용은 상수에 가까워집니다.
  • 확장은 저장문보다 먼저 실행됩니다. 확장이 실패하면 저장문에 도달하지 않고, 정상 add 완료 뒤에는 size가 하나 증가합니다.
  • 초기 용량은 예상 데이터 크기와 낭비 메모리 사이의 선택값이며 정답 하나가 아닙니다.

복사 뒤 배열을 교체하는 MyArrayList

DynamicTitleList는 길이 0에서도 시작할 수 있고 필요 용량보다 작은 배열을 만들지 않습니다.

제네릭 배열을 직접 만들 수 없으므로 Object[]를 저장 지점으로 쓰고 get 한 곳에서만 비검사 캐스팅을 수행합니다. 아래 main은 get을 호출하지 않습니다.

src/DynamicTitleList.java
import java.util.Arrays;

public final class DynamicTitleList {
    public static void main(String[] args) {
        MyArrayList<String> list = new MyArrayList<>(1);
        list.add("array");
        list.add("growth");
        list.add("copy");
        System.out.println(list);
        System.out.println("size=" + list.size() + ", capacity=" + list.capacity());
    }

    private static final class MyArrayList<E> {
        private Object[] values;
        private int size;

        MyArrayList(int initialCapacity) {
            if (initialCapacity < 0) throw new IllegalArgumentException("capacity");
            values = new Object[initialCapacity];
        }

        void add(E value) {
            ensureCapacity(size + 1);
            values[size++] = value;
        }

        @SuppressWarnings("unchecked")
        E get(int index) {
            if (index < 0 || index >= size) throw new IndexOutOfBoundsException(index);
            return (E) values[index];
        }

        private void ensureCapacity(int required) {
            if (required <= values.length) return;
            int doubled = values.length == 0 ? 1 : values.length * 2;
            values = Arrays.copyOf(values, Math.max(doubled, required));
        }

        int size() {
            return size;
        }

        int capacity() {
            return values.length;
        }

        public String toString() {
            return Arrays.toString(Arrays.copyOf(values, size));
        }
    }
}

성장 정책을 수열로 확인

초기 용량이 1이고 두 배 전략을 쓰면 세 번째 삽입까지 용량은 1, 2, 4로 변합니다.

네 번째는 남은 칸을 사용하고 다섯 번째에서 8로 확장됩니다.

확장은 모든 add에서 일어나는 일이 아니라 특정 접점에서만 발생합니다.

세 번의 add에서 용량은 1·2·4가 된다

세 실제 add에서 두 번째는 한 칸, 세 번째는 두 칸을 복사하며 size/capacity가 변합니다. 매번 확장되는 것이 아닌 실제 저장소 변화를 보여 줄 수 있습니다.

세 번의 add에서 용량은 1·2·4가 된다

DynamicTitleList의 세 번의 끝 추가에서 필요한 크기와 Arrays.copyOf의 실제 확장 분기를 추적하고 최종 stdout을 구분합니다. 별도 CLI의 System.arraycopy와 섞지 않습니다.

실제 배열 · 용량 1 → 2 → 4

세 번의 add에서 용량은 1·2·4가 된다

첫 추가는 빈 칸을 사용하고, 다음 두 추가는 Arrays.copyOf로 길이를 늘립니다. 출력 목록은 사용 중인 세 칸만 보여 줍니다.

실제 배열 확장과 사용 구간의 출력DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는1칸, 셋째는2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는null칸은 목록 출력에서 제외합니다.
첫 추가 · array필요 1 ≤ 용량 1복사 0칸 / size=1
연결 관계첫 추가 · array · 필요 1 ≤ 용량 1 · 복사 0칸 / size=1 → 둘째 추가 · growth · 필요 2 > 용량 1 · 1칸 복사 / 새 용량 2 · 저장 후 size=2
둘째 추가 · growth필요 2 > 용량 11칸 복사 / 새 용량 2저장 후 size=2
연결 관계둘째 추가 · growth · 필요 2 > 용량 1 · 1칸 복사 / 새 용량 2 · 저장 후 size=2 → 셋째 추가 · copy · 필요 3 > 용량 2 · 2칸 복사 / 새 용량 4 · 저장 후 size=3
셋째 추가 · copy필요 3 > 용량 22칸 복사 / 새 용량 4저장 후 size=3
연결 관계셋째 추가 · copy · 필요 3 > 용량 2 · 2칸 복사 / 새 용량 4 · 저장 후 size=3 → 사용 구간 출력 · array, growth, copy · 남는 1칸은 null · size=3, capacity=4
사용 구간 출력array, growth, copy남는 1칸은 nullsize=3, capacity=4

실선: 원 add와 출력 순서복사는 실제 Arrays.copyOf

  1. add("array")

    용량 검사와 복사 · 소스 추적
    required=1, capacity=1
    복사 없음
    정상 완료 상태 또는 출력
    size=1, capacity=1
    [array]
  2. add("growth")

    용량 검사와 복사 · 소스 추적
    required=2 > 1
    Arrays.copyOf 길이 1 → 2
    기존 1칸 복사
    정상 완료 상태 또는 출력
    size=2, capacity=2
    [array, growth]
  3. add("copy")

    용량 검사와 복사 · 소스 추적
    required=3 > 2
    Arrays.copyOf 길이 2 → 4
    기존 2칸 복사
    정상 완료 상태 또는 출력
    size=3, capacity=4
    [array, growth, copy, null]
  4. 마지막 출력

    용량 검사와 복사 · 소스 추적
    toString()은 사용 구간만 표시
    get은 이 main에서 호출하지 않음
    정상 완료 상태 또는 출력
    [array, growth, copy]
    size=3, capacity=4

이 예의 조건

  • 실제 Arrays.copyOf이며 미사용 null 칸은 목록 출력에서 제외한다.
관계도의 보충 설명
원 도표의 전체 관계·라벨·조건
구분내용
2DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는 1칸, 셋째는 2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는 null 칸은 목록 출력에서 제외합니다.
5복사 0칸
6size=1
91칸 복사
10새 용량 2
142칸 복사
15새 용량 4
원 도표의 설명과 주석
구분내용
설명DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는 1칸, 셋째는 2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는 null 칸은 목록 출력에서 제외합니다.
전체 읽기 정보세 번의 add에서 용량은 1·2·4가 된다 세 번의 add에서 용량은 1·2·4가 된다 DynamicTitleList의 세 번의 끝 추가에서 필요한 크기와 Arrays.copyOf의 실제 확장 분기를 추적하고 최종 stdout을 구분합니다. 별도 CLI의 System.arraycopy와 섞지 않습니다. 실제 배열 · 용량 1 → 2 → 4 세 번의 add에서 용량은 1·2·4가 된다 첫 추가는 빈 칸을 사용하고, 다음 두 추가는 Arrays.copyOf로 길이를 늘립니다. 출력 목록은 사용 중인 세 칸만 보여 줍니다. add("array") 용량 검사와 복사 · 소스 추적 required=1, capacity=1 복사 없음 정상 완료 상태 또는 출력 size=1, capacity=1 [array] add("growth") 용량 검사와 복사 · 소스 추적 required=2 > 1 Arrays.copyOf 길이 1 → 2 기존 1칸 복사 정상 완료 상태 또는 출력 size=2, capacity=2 [array, growth] add("copy") 용량 검사와 복사 · 소스 추적 required=3 > 2 Arrays.copyOf 길이 2 → 4 기존 2칸 복사 정상 완료 상태 또는 출력 size=3, capacity=4 [array, growth, copy, null] 마지막 출력 용량 검사와 복사 · 소스 추적 toString() 은 사용 구간만 표시 get 은 이 main에서 호출하지 않음 정상 완료 상태 또는 출력 [array, growth, copy] size=3, capacity=4
예의 값과 변화
관찰·상황값·보충 정보변화·이유
첫 추가

array는 현재 용량 1에 저장됩니다.

  • size: 1
  • capacity: 1
  • 복사: 0칸
  • 빈 공간에 넣을 때는 확장이 필요 없다.
둘째 추가

growth 저장 전에 용량 2를 만들며 한 칸을 복사합니다.

  • size: 2
  • capacity: 2
  • 복사: 1칸
  • 필요 크기가 용량 1을 넘어서 첫 확장을 수행한다.
셋째와 출력

copy 저장 전에 두 칸을 복사하여 용량 4가 됩니다.

  • size: 3
  • capacity: 4
  • 사용 목록: array,growth,copy
  • 미사용: null 1칸
  • 사용 개수와 할당 용량을 다르게 유지한다.

세 번의 add에서 용량은 1·2·4가 된다

세 실제 add에서 두 번째는 한 칸, 세 번째는 두 칸을 복사하며 size/capacity가 변합니다. 매번 확장되는 것이 아닌 실제 저장소 변화를 보여 줄 수 있습니다.

세 번의 add에서 용량은 1·2·4가 된다

DynamicTitleList의 세 번의 끝 추가에서 필요한 크기와 Arrays.copyOf의 실제 확장 분기를 추적하고 최종 stdout을 구분합니다. 별도 CLI의 System.arraycopy와 섞지 않습니다.

실제 배열 · 용량 1 → 2 → 4

세 번의 add에서 용량은 1·2·4가 된다

첫 추가는 빈 칸을 사용하고, 다음 두 추가는 Arrays.copyOf로 길이를 늘립니다. 출력 목록은 사용 중인 세 칸만 보여 줍니다.

실제 배열 확장과 사용 구간의 출력DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는1칸, 셋째는2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는null칸은 목록 출력에서 제외합니다.
첫 추가 · array필요 1 ≤ 용량 1복사 0칸 / size=1
연결 관계첫 추가 · array · 필요 1 ≤ 용량 1 · 복사 0칸 / size=1 → 둘째 추가 · growth · 필요 2 > 용량 1 · 1칸 복사 / 새 용량 2 · 저장 후 size=2
둘째 추가 · growth필요 2 > 용량 11칸 복사 / 새 용량 2저장 후 size=2
연결 관계둘째 추가 · growth · 필요 2 > 용량 1 · 1칸 복사 / 새 용량 2 · 저장 후 size=2 → 셋째 추가 · copy · 필요 3 > 용량 2 · 2칸 복사 / 새 용량 4 · 저장 후 size=3
셋째 추가 · copy필요 3 > 용량 22칸 복사 / 새 용량 4저장 후 size=3
연결 관계셋째 추가 · copy · 필요 3 > 용량 2 · 2칸 복사 / 새 용량 4 · 저장 후 size=3 → 사용 구간 출력 · array, growth, copy · 남는 1칸은 null · size=3, capacity=4
사용 구간 출력array, growth, copy남는 1칸은 nullsize=3, capacity=4

실선: 원 add와 출력 순서복사는 실제 Arrays.copyOf

  1. add("array")

    용량 검사와 복사 · 소스 추적
    required=1, capacity=1
    복사 없음
    정상 완료 상태 또는 출력
    size=1, capacity=1
    [array]
  2. add("growth")

    용량 검사와 복사 · 소스 추적
    required=2 > 1
    Arrays.copyOf 길이 1 → 2
    기존 1칸 복사
    정상 완료 상태 또는 출력
    size=2, capacity=2
    [array, growth]
  3. add("copy")

    용량 검사와 복사 · 소스 추적
    required=3 > 2
    Arrays.copyOf 길이 2 → 4
    기존 2칸 복사
    정상 완료 상태 또는 출력
    size=3, capacity=4
    [array, growth, copy, null]
  4. 마지막 출력

    용량 검사와 복사 · 소스 추적
    toString()은 사용 구간만 표시
    get은 이 main에서 호출하지 않음
    정상 완료 상태 또는 출력
    [array, growth, copy]
    size=3, capacity=4

이 예의 조건

  • 실제 Arrays.copyOf이며 미사용 null 칸은 목록 출력에서 제외한다.

관계도의 보충 설명

원 도표의 전체 관계·라벨·조건
구분내용
2DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는 1칸, 셋째는 2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는 null 칸은 목록 출력에서 제외합니다.
5복사 0칸
6size=1
91칸 복사
10새 용량 2
142칸 복사
15새 용량 4
원 도표의 설명과 주석
구분내용
설명DynamicTitleList는 array/growth/copy를 넣습니다. 첫 추가는 복사 없고 둘째는 1칸, 셋째는 2칸을 실제 Arrays.copyOf로 복사합니다. 실선은 각 add와 마지막 출력의 순서이며 남는 null 칸은 목록 출력에서 제외합니다.
전체 읽기 정보세 번의 add에서 용량은 1·2·4가 된다 세 번의 add에서 용량은 1·2·4가 된다 DynamicTitleList의 세 번의 끝 추가에서 필요한 크기와 Arrays.copyOf의 실제 확장 분기를 추적하고 최종 stdout을 구분합니다. 별도 CLI의 System.arraycopy와 섞지 않습니다. 실제 배열 · 용량 1 → 2 → 4 세 번의 add에서 용량은 1·2·4가 된다 첫 추가는 빈 칸을 사용하고, 다음 두 추가는 Arrays.copyOf로 길이를 늘립니다. 출력 목록은 사용 중인 세 칸만 보여 줍니다. add("array") 용량 검사와 복사 · 소스 추적 required=1, capacity=1 복사 없음 정상 완료 상태 또는 출력 size=1, capacity=1 [array] add("growth") 용량 검사와 복사 · 소스 추적 required=2 > 1 Arrays.copyOf 길이 1 → 2 기존 1칸 복사 정상 완료 상태 또는 출력 size=2, capacity=2 [array, growth] add("copy") 용량 검사와 복사 · 소스 추적 required=3 > 2 Arrays.copyOf 길이 2 → 4 기존 2칸 복사 정상 완료 상태 또는 출력 size=3, capacity=4 [array, growth, copy, null] 마지막 출력 용량 검사와 복사 · 소스 추적 toString() 은 사용 구간만 표시 get 은 이 main에서 호출하지 않음 정상 완료 상태 또는 출력 [array, growth, copy] size=3, capacity=4
예의 값과 변화
관찰·상황값·보충 정보변화·이유
첫 추가

array는 현재 용량 1에 저장됩니다.

  • size: 1
  • capacity: 1
  • 복사: 0칸
  • 빈 공간에 넣을 때는 확장이 필요 없다.
둘째 추가

growth 저장 전에 용량 2를 만들며 한 칸을 복사합니다.

  • size: 2
  • capacity: 2
  • 복사: 1칸
  • 필요 크기가 용량 1을 넘어서 첫 확장을 수행한다.
셋째와 출력

copy 저장 전에 두 칸을 복사하여 용량 4가 됩니다.

  • size: 3
  • capacity: 4
  • 사용 목록: array,growth,copy
  • 미사용: null 1칸
  • 사용 개수와 할당 용량을 다르게 유지한다.

그래서 한 번의 비싼 복사와 장기간의 값싼 끝 추가를 함께 계산해야 합니다.

초기 길이가 0이면 단순한 length * 2도 계속 0입니다.

최솟값 1과 필요 용량을 함께 비교해야 첫 삽입이 가능합니다.

또한 필요 용량이 두 배보다 큰 대량 추가 API를 생각한다면 Math.max(doubled, required)가 필요합니다.


상환 분석과 평균 실행 시간의 차이

n개의 원소를 넣는 동안 복사되는 원소 수는 1, 2, 4처럼 기하급수로 늘고 그 합은 최종 크기의 일정 배수 안에 머뭅니다.

이 때문에 끝 추가의 상환 비용을 O(1)이라고 설명합니다.

처음 용량이 1인 이 구현에서 10번 끝 추가하면 확장 때 복사하는 기존 칸은 1 + 2 + 4 + 8 = 15개입니다. 새 값을 저장하는 10회까지 합하면 25회입니다. 모든 추가가 15칸을 복사하는 것은 아니며, 다섯 번째처럼 확장이 필요한 호출에 작업이 모입니다. 이 계산은 배열 생성 비용을 생략한 칸 복사·저장 모델이지만, 전체 추가 수에 비례한다는 상환 설명을 직접 확인하게 합니다.

계속 추적하기

같은 실행에서 열한 번째 값을 추가하면 확장 횟수, 마지막 용량, 누적 기존 칸 복사 수가 각각 어떻게 바뀔까요? 아직 실행하지 말고 열 번째 완료 상태 size=10, capacity=16에서 시작해 보세요.

열한 번째 추가 확인

필요 크기 11은 용량 16 이내라 확장하지 않습니다. 확장 횟수 4회, 용량 16, 누적 기존 칸 복사 15개가 유지되고 새 값 저장만 한 번 늘어 총 26회가 됩니다. 다음 확장은 열일곱 번째 추가에서 필요합니다. 이 수열은 여기서 직접 만든 두 배 전략의 결과이며 표준 ArrayList의 내부 성장 배수를 약속하지 않습니다.

특정 확장 add가 O(n)이라는 사실은 그대로이며 지연 시간 상한이 중요한 시스템에서는 별도 대책이 필요합니다.

실시간 응답이 중요하면 예상 최대치에 가까운 초기 용량을 주거나, 입력을 청크로 나누거나, 확장 시점을 요청 바깥으로 옮기는 선택을 검토합니다.

메모리 낭비를 줄이는 것과 복사 횟수를 줄이는 것은 서로 반대 방향의 목표입니다.


복사 범위와 상태 갱신 순서

이 구현의 Arrays.copyOf는 기존 배열 길이의 값을 복사합니다. 한 칸씩 추가해 배열이 가득 찼을 때 확장하므로 이 시점에는 기존 길이와 size가 같습니다.

참조 배열의 빈 칸은 null로 초기화됩니다.

새 배열 생성과 복사가 성공한 뒤 values를 교체합니다. 다음 values[size++] = value에서 size++는 인덱스를 평가할 때 먼저 일어나며, 정상 완료 시 새 값과 증가한 size가 반영됩니다.


저장량이 늘어나는 게시글

게시글 저장소에 기록 수 상한을 두지 않으려면 저장소가 스스로 확장해야 합니다.

CLI는 두 개의 입력으로 시작하지만 이후 같은 add 규칙을 유지합니다.

초기 용량은 외부 기능이 아니라 성능 힌트입니다.

app/PostRepositoryCliCH142.java
public final class PostRepositoryCliCH142 {
    public static void main(String[] args) {
        PostRepository repository = new PostRepository();
        repository.add("capacity", 30);
        repository.add("array-copy", 50);
        repository.print();
        System.out.println("total=" + repository.totalViewCount());
    }

    private static final class PostRepository {
        private Entry[] entries = new Entry[2];
        private int size;

        void add(String title, int viewCount) {
            if (title == null || title.isBlank()) throw new IllegalArgumentException("title");
            if (viewCount <= 0) throw new IllegalArgumentException("viewCount");
            ensureCapacity(size + 1);
            entries[size++] = new Entry(title, viewCount);
        }

        private void ensureCapacity(int required) {
            if (required <= entries.length) return;
            Entry[] grown = new Entry[Math.max(required, entries.length * 2)];
            System.arraycopy(entries, 0, grown, 0, size);
            entries = grown;
        }

        int totalViewCount() {
            int total = 0;
            for (int i = 0; i < size; i++) {
                total += entries[i].viewCount();
            }
            return total;
        }

        void print() {
            for (int i = 0; i < size; i++) {
                Entry entry = entries[i];
                System.out.println(i + ":" + entry.title() + "=" + entry.viewCount());
            }
        }
    }

    private record Entry(String title, int viewCount) {}
}

이 단계의 CLI는 초기 두 칸만 사용하지만 세 번째 명령을 추가해도 같은 add 경로가 확장하도록 설계되었습니다.

이 main은 확장 분기를 실행하지 않습니다. 세 번째 항목을 추가하는 별도 검증에서는 기존 두 Entry가 복사 후에도 같은 순서와 조회수를 유지하는지 확인해야 합니다.

성장 정책은 기능 출력에 나타나지 않는 내부 성능 결정입니다.


초기 용량과 성장 배수 결정

질문관찰할 값선택 또는 조치
증가 폭이 예측 가능한가최종 size초기 용량 지정
끝 추가가 주 연산인가확장 횟수배수 성장 사용
메모리 여유가 작은가미사용 슬롯성장 배수 조정
대량 복사가 부담인가복사 시간청크 또는 연결 구조 검토

매번 한 칸씩 늘리면 n개 삽입에 복사량이 누적되어 제곱 비용이 됩니다.

배수 성장은 빈 슬롯을 조금 남기는 대신 복사 횟수를 크게 줄입니다.

실제 초기 용량은 예상 크기 분포를 측정한 뒤 정합니다.


연습 문제

초기 용량 1에서 원소 10개를 끝에 추가한다고 가정합니다.

확장이 일어난 횟수와 마지막 용량을 출력하는 작은 시뮬레이터를 작성하세요.

정답과 해설

삽입 직전 필요 크기가 용량을 넘을 때만 두 배로 늘립니다.

원소를 실제로 저장하지 않아도 size와 용량 전이만으로 성장 비용을 확인할 수 있습니다.

exercise/CapacityGrowthTraceSolution.java
public final class CapacityGrowthTraceSolution {
    public static void main(String[] args) {
        int size = 0;
        int capacity = 1;
        int growths = 0;
        while (size < 10) {
            int required = size + 1;
            if (required > capacity) {
                capacity = Math.max(required, capacity * 2);
                growths++;
            }
            size++;
        }
        System.out.println("growths=" + growths + ", capacity=" + capacity);
    }
}

2, 4, 8, 16으로 네 번 커지므로 결과는 growths=4, capacity=16입니다.

10번 추가 모형의 확장 지점은 네 번이다

숫자 성장 모델은 add 2/3/5/9에서만 확장하여 size 10/capacity 16이 됩니다. 실제 배열 복사가 아닌 모델이라는 조건을 유지하며 확장 트리거를 추적합니다.

10번 추가 모형의 확장 지점은 네 번이다

CapacityGrowthTraceSolution이 배열을 복사하지 않고 size와 capacity 숫자만 갱신하며 추가 순번 2·3·5·9에서 용량을 늘리는 과정을 추적합니다.

숫자 모형 · 확장 횟수

10번 추가 모형의 확장 지점은 네 번이다

추가 순번 2·3·5·9에서 필요한 크기가 현재 용량을 넘습니다. 용량은 2·4·8·16으로 바뀌고 마지막 추가에서는 확장하지 않습니다.

숫자 모델의 확장 접점과 마지막 용량CapacityGrowthTraceSolution의 숫자 모델입니다. 추가2/3/5/9에서 용량2/4/8/16으로 커지고 열 번 뒤 growths4/capacity16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행시간을 측정하지 않습니다.
숫자 모델 초기size=0 / capacity=1growths=0
연결 관계숫자 모델 초기 · size=0 / capacity=1 · growths=0 → 확장 접점 · add 2: 용량 2 · add 3: 용량 4 · add 5: 용량 8 · add 9: 용량 16
확장 접점add 2: 용량 2add 3: 용량 4add 5: 용량 8add 9: 용량 16
연결 관계확장 접점 · add 2: 용량 2 · add 3: 용량 4 · add 5: 용량 8 · add 9: 용량 16 → 열 번 추가 후 · size=10 / capacity=16 · growths=4
열 번 추가 후size=10 / capacity=16growths=4

실선: 계산 모델의 진행원 예제는 실제 배열을만들거나 복사하지 않음

10번 추가 모형의 확장 지점은 네 번이다
추가 순번 · 숫자 모형추가 직전 required와 용량확장 후 capacity · growths
2번째required=2 > capacity=1capacity=2, growths=1
3번째required=3 > capacity=2capacity=4, growths=2
5번째required=5 > capacity=4capacity=8, growths=3
9번째required=9 > capacity=8capacity=16, growths=4
10번째 완료
size=10 · 마지막 추가는 확장 없음
실제 배열 복사나 시간 측정은 하지 않음
실제 출력:
growths=4, capacity=16
2번째
추가 직전 required와 용량
required=2 > capacity=1
확장 후 capacity · growths
capacity=2, growths=1
3번째
추가 직전 required와 용량
required=3 > capacity=2
확장 후 capacity · growths
capacity=4, growths=2
5번째
추가 직전 required와 용량
required=5 > capacity=4
확장 후 capacity · growths
capacity=8, growths=3
9번째
추가 직전 required와 용량
required=9 > capacity=8
확장 후 capacity · growths
capacity=16, growths=4
10번째 완료
추가 직전 required와 용량
size=10 · 마지막 추가는 확장 없음
실제 배열 복사나 시간 측정은 하지 않음
확장 후 capacity · growths
실제 출력:
growths=4, capacity=16

이 예의 조건

  • 숫자 모델이며 실제 배열 복사/시간 측정이 아니다.
관계도의 보충 설명
원 도표의 전체 관계·라벨·조건
구분내용
2CapacityGrowthTraceSolution의 숫자 모델입니다. 추가 2/3/5/9에서 용량 2/4/8/16으로 커지고 열 번 뒤 growths 4/capacity 16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행 시간을 측정하지 않습니다.
4size=0
5capacity=1
14capacity=16
원 도표의 설명과 주석
구분내용
설명CapacityGrowthTraceSolution의 숫자 모델입니다. 추가 2/3/5/9에서 용량 2/4/8/16으로 커지고 열 번 뒤 growths 4/capacity 16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행 시간을 측정하지 않습니다.
전체 읽기 정보10번 추가 모형의 확장 지점은 네 번이다 10번 추가 모형의 확장 지점은 네 번이다 CapacityGrowthTraceSolution이 배열을 복사하지 않고 size와 capacity 숫자만 갱신하며 추가 순번 2·3·5·9에서 용량을 늘리는 과정을 추적합니다. 숫자 모형 · 확장 횟수 10번 추가 모형의 확장 지점은 네 번이다 추가 순번 2·3·5·9에서 필요한 크기가 현재 용량을 넘습니다. 용량은 2·4·8·16으로 바뀌고 마지막 추가에서는 확장하지 않습니다. 10번 추가 모형의 확장 지점은 네 번이다 추가 순번 · 숫자 모형 추가 직전 required와 용량 확장 후 capacity · growths 2번째 required=2 > capacity=1 capacity=2, growths=1 3번째 required=3 > capacity=2 capacity=4, growths=2 5번째 required=5 > capacity=4 capacity=8, growths=3 9번째 required=9 > capacity=8 capacity=16, growths=4 10번째 완료 size=10 · 마지막 추가는 확장 없음 실제 배열 복사나 시간 측정은 하지 않음 실제 출력: growths=4, capacity=16 2번째 추가 직전 required와 용량 required=2 > capacity=1 확장 후 capacity · growths capacity=2, growths=1 3번째 추가 직전 required와 용량 required=3 > capacity=2 확장 후 capacity · growths capacity=4, growths=2 5번째 추가 직전 required와 용량 required=5 > capacity=4 확장 후 capacity · growths capacity=8, growths=3 9번째 추가 직전 required와 용량 required=9 > capacity=8 확장 후 capacity · growths capacity=16, growths=4 10번째 완료 추가 직전 required와 용량 size=10 · 마지막 추가는 확장 없음 실제 배열 복사나 시간 측정은 하지 않음 확장 후 capacity · growths 실제 출력: growths=4, capacity=16
예의 값과 변화
관찰·상황값·보충 정보변화·이유
초기 모델

용량 1과 size 0에서 시작합니다.

  • size: 0
  • capacity: 1
  • growths: 0
  • 모델의 확장 조건은 다음 추가가 현재 용량을 넘는 것이다.
확장 접점

add 2/3/5/9에서 용량을 두 배로 바꿉니다.

  • 접점: 2→2,3→4,5→8,9→16
  • growths: 4
  • 사이의 추가는 기존 여유 용량을 사용한다.
열 번 뒤

최종 모델 상태를 읽습니다.

  • size: 10
  • capacity: 16
  • growths: 4
  • 10회 추가와 4회 확장은 다른 횟수다.

10번 추가 모형의 확장 지점은 네 번이다

숫자 성장 모델은 add 2/3/5/9에서만 확장하여 size 10/capacity 16이 됩니다. 실제 배열 복사가 아닌 모델이라는 조건을 유지하며 확장 트리거를 추적합니다.

10번 추가 모형의 확장 지점은 네 번이다

CapacityGrowthTraceSolution이 배열을 복사하지 않고 size와 capacity 숫자만 갱신하며 추가 순번 2·3·5·9에서 용량을 늘리는 과정을 추적합니다.

숫자 모형 · 확장 횟수

10번 추가 모형의 확장 지점은 네 번이다

추가 순번 2·3·5·9에서 필요한 크기가 현재 용량을 넘습니다. 용량은 2·4·8·16으로 바뀌고 마지막 추가에서는 확장하지 않습니다.

숫자 모델의 확장 접점과 마지막 용량CapacityGrowthTraceSolution의 숫자 모델입니다. 추가2/3/5/9에서 용량2/4/8/16으로 커지고 열 번 뒤 growths4/capacity16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행시간을 측정하지 않습니다.
숫자 모델 초기size=0 / capacity=1growths=0
연결 관계숫자 모델 초기 · size=0 / capacity=1 · growths=0 → 확장 접점 · add 2: 용량 2 · add 3: 용량 4 · add 5: 용량 8 · add 9: 용량 16
확장 접점add 2: 용량 2add 3: 용량 4add 5: 용량 8add 9: 용량 16
연결 관계확장 접점 · add 2: 용량 2 · add 3: 용량 4 · add 5: 용량 8 · add 9: 용량 16 → 열 번 추가 후 · size=10 / capacity=16 · growths=4
열 번 추가 후size=10 / capacity=16growths=4

실선: 계산 모델의 진행원 예제는 실제 배열을만들거나 복사하지 않음

10번 추가 모형의 확장 지점은 네 번이다
추가 순번 · 숫자 모형추가 직전 required와 용량확장 후 capacity · growths
2번째required=2 > capacity=1capacity=2, growths=1
3번째required=3 > capacity=2capacity=4, growths=2
5번째required=5 > capacity=4capacity=8, growths=3
9번째required=9 > capacity=8capacity=16, growths=4
10번째 완료
size=10 · 마지막 추가는 확장 없음
실제 배열 복사나 시간 측정은 하지 않음
실제 출력:
growths=4, capacity=16
2번째
추가 직전 required와 용량
required=2 > capacity=1
확장 후 capacity · growths
capacity=2, growths=1
3번째
추가 직전 required와 용량
required=3 > capacity=2
확장 후 capacity · growths
capacity=4, growths=2
5번째
추가 직전 required와 용량
required=5 > capacity=4
확장 후 capacity · growths
capacity=8, growths=3
9번째
추가 직전 required와 용량
required=9 > capacity=8
확장 후 capacity · growths
capacity=16, growths=4
10번째 완료
추가 직전 required와 용량
size=10 · 마지막 추가는 확장 없음
실제 배열 복사나 시간 측정은 하지 않음
확장 후 capacity · growths
실제 출력:
growths=4, capacity=16

이 예의 조건

  • 숫자 모델이며 실제 배열 복사/시간 측정이 아니다.

관계도의 보충 설명

원 도표의 전체 관계·라벨·조건
구분내용
2CapacityGrowthTraceSolution의 숫자 모델입니다. 추가 2/3/5/9에서 용량 2/4/8/16으로 커지고 열 번 뒤 growths 4/capacity 16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행 시간을 측정하지 않습니다.
4size=0
5capacity=1
14capacity=16
원 도표의 설명과 주석
구분내용
설명CapacityGrowthTraceSolution의 숫자 모델입니다. 추가 2/3/5/9에서 용량 2/4/8/16으로 커지고 열 번 뒤 growths 4/capacity 16입니다. 실선은 계산 진행이며 이 모델이 실제 배열 복사나 실행 시간을 측정하지 않습니다.
전체 읽기 정보10번 추가 모형의 확장 지점은 네 번이다 10번 추가 모형의 확장 지점은 네 번이다 CapacityGrowthTraceSolution이 배열을 복사하지 않고 size와 capacity 숫자만 갱신하며 추가 순번 2·3·5·9에서 용량을 늘리는 과정을 추적합니다. 숫자 모형 · 확장 횟수 10번 추가 모형의 확장 지점은 네 번이다 추가 순번 2·3·5·9에서 필요한 크기가 현재 용량을 넘습니다. 용량은 2·4·8·16으로 바뀌고 마지막 추가에서는 확장하지 않습니다. 10번 추가 모형의 확장 지점은 네 번이다 추가 순번 · 숫자 모형 추가 직전 required와 용량 확장 후 capacity · growths 2번째 required=2 > capacity=1 capacity=2, growths=1 3번째 required=3 > capacity=2 capacity=4, growths=2 5번째 required=5 > capacity=4 capacity=8, growths=3 9번째 required=9 > capacity=8 capacity=16, growths=4 10번째 완료 size=10 · 마지막 추가는 확장 없음 실제 배열 복사나 시간 측정은 하지 않음 실제 출력: growths=4, capacity=16 2번째 추가 직전 required와 용량 required=2 > capacity=1 확장 후 capacity · growths capacity=2, growths=1 3번째 추가 직전 required와 용량 required=3 > capacity=2 확장 후 capacity · growths capacity=4, growths=2 5번째 추가 직전 required와 용량 required=5 > capacity=4 확장 후 capacity · growths capacity=8, growths=3 9번째 추가 직전 required와 용량 required=9 > capacity=8 확장 후 capacity · growths capacity=16, growths=4 10번째 완료 추가 직전 required와 용량 size=10 · 마지막 추가는 확장 없음 실제 배열 복사나 시간 측정은 하지 않음 확장 후 capacity · growths 실제 출력: growths=4, capacity=16
예의 값과 변화
관찰·상황값·보충 정보변화·이유
초기 모델

용량 1과 size 0에서 시작합니다.

  • size: 0
  • capacity: 1
  • growths: 0
  • 모델의 확장 조건은 다음 추가가 현재 용량을 넘는 것이다.
확장 접점

add 2/3/5/9에서 용량을 두 배로 바꿉니다.

  • 접점: 2→2,3→4,5→8,9→16
  • growths: 4
  • 사이의 추가는 기존 여유 용량을 사용한다.
열 번 뒤

최종 모델 상태를 읽습니다.

  • size: 10
  • capacity: 16
  • growths: 4
  • 10회 추가와 4회 확장은 다른 횟수다.

마지막 size 10과 용량 16의 차이는 다음 삽입을 싸게 만들기 위해 미리 지불한 여유입니다.


동적 배열 완성 기준

빈 배열에서도 첫 add가 성공해야 하고, 확장 직후 이전 원소의 순서가 보존되어야 합니다.

용량은 절대로 size보다 작을 수 없습니다.

한 칸 성장과 배수 성장의 누적 복사량을 비교해 설명할 수 있다면 상환 비용까지 이해한 것입니다.