๐ŸŽฏ1์ฃผ์ฐจ Unit 6.3 โ€” ArrayList vs LinkedList

Psjยท์–ด์ œ

F-lab

๋ชฉ๋ก ๋ณด๊ธฐ
43/52

๐ŸŽฏ Unit 6.3 โ€” ArrayList vs LinkedList โ˜…โ˜…โ˜…

F-lab Java 1์ฃผ์ฐจ / Phase 6 / Unit 6.3 ๋ณธ๊ฒฉ ํ•™์Šต ์ž๋ฃŒ
9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ ํ˜•์‹์œผ๋กœ ๊นŠ์ด ํŒŒํ—ค์นœ๋‹ค.

์„ ์ˆ˜ ์ง€์‹: Phase 4-5 (๋ฉ”๋ชจ๋ฆฌ, GC), Unit 6.1-6.2 (String, StringBuilder)
๋‹ค์Œ Unit: 6.4 โ€” HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ โ˜…โ˜…โ˜…

์ด Unit์˜ ์˜๋ฏธ: ์ž๋ฐ” ์ปฌ๋ ‰์…˜์˜ ์‹œ์ž‘์ .
๋ฉด์ ‘ ๋‹จ๊ณจ ("์–ธ์ œ ArrayList? ์–ธ์ œ LinkedList?") + ์‹ค๋ฌด (CPU ์บ์‹œ ์ง„์‹ค).
Big-O ๋งŒ์œผ๋กœ ๊ฒฐ์ •ํ•˜๋ฉด ํ‹€๋ฆฐ๋‹ค โ€” ์ด Unit ์˜ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€.


๐ŸŒ 1. ์„ธ์ƒ ์† ๋น„์œ 

ArrayList = ์•„ํŒŒํŠธ / LinkedList = ๋ณด๋ฌผ์ฐพ๊ธฐ ์‚ฌ์Šฌ

๋‘ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ฐจ์ด๋ฅผ ์ผ์ƒ ๋น„์œ ๋กœ ํ’€์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ArrayList โ€” ์•„ํŒŒํŠธ ๋‹จ์ง€

[101๋™] [102๋™] [103๋™] [104๋™] [105๋™] [106๋™] [107๋™]
   โ†‘                                                 โ†‘
  ์‹œ์ž‘                                              ๋

ํŠน์ง•:

  • ํ˜ธ์ˆ˜๊ฐ€ ์—ฐ์†๋œ ๋ฒˆํ˜ธ
  • "104๋™ ๊ฐ€์ฃผ์„ธ์š”" โ†’ ์ฆ‰์‹œ (๋ฒˆํ˜ธ๋กœ ์ง์ ‘)
  • ์ƒˆ ๋™์„ ์ค‘๊ฐ„์— ๋„ฃ์œผ๋ ค๋ฉด? โ†’ ๋’ค์˜ ๋ชจ๋“  ๋™ ๋ฒˆํ˜ธ ๋ณ€๊ฒฝ โš ๏ธ
  • ๋งˆ์ง€๋ง‰์— ์ถ”๊ฐ€? โ†’ ๋นˆ ๋ถ€์ง€์— ๊ทธ๋ƒฅ โœ“

ํ•ต์‹ฌ: ์ธ๋ฑ์Šค ์ง์ ‘ ์ ‘๊ทผ ๋น ๋ฆ„, ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ ๋А๋ฆผ.


LinkedList โ€” ๋ณด๋ฌผ์ฐพ๊ธฐ ์‚ฌ์Šฌ

[A ๋ณด๋ฌผ์ƒ์ž]
  โ†’ "๋‹ค์Œ ์œ„์น˜๋Š” X ์ขŒํ‘œ"
[B ๋ณด๋ฌผ์ƒ์ž]
  โ†’ "๋‹ค์Œ ์œ„์น˜๋Š” Y ์ขŒํ‘œ"
[C ๋ณด๋ฌผ์ƒ์ž]
  โ†’ "๋‹ค์Œ ์œ„์น˜๋Š” Z ์ขŒํ‘œ"
[D ๋ณด๋ฌผ์ƒ์ž]
  โ†’ "์—ฌ๊ธฐ๊ฐ€ ๋งˆ์ง€๋ง‰"

ํŠน์ง•:

  • ๋‹ค์Œ ๋ณด๋ฌผ ์œ„์น˜๋งŒ ํ‘œ์‹œ
  • "3๋ฒˆ์งธ ๋ณด๋ฌผ ์ฐพ์•„์ฃผ์„ธ์š”" โ†’ A โ†’ B โ†’ C ์ˆœ์ฐจ ํƒ์ƒ‰
  • ์ƒˆ ๋ณด๋ฌผ์ƒ์ž๋ฅผ ์ค‘๊ฐ„์—? โ†’ ์•ž๋’ค ํ™”์‚ดํ‘œ๋งŒ ์ˆ˜์ • โœ“
  • ๋์—์„œ 4๋ฒˆ์งธ? โ†’ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ํƒ์ƒ‰? (์ด์ค‘ ์—ฐ๊ฒฐ์ด๋ฉด ๋๋ถ€ํ„ฐ 4๋ฒˆ)

ํ•ต์‹ฌ: ์ˆœ์ฐจ ํƒ์ƒ‰ ๋А๋ฆผ, ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ ๋น ๋ฆ„.


ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

"๋‘ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” Big-O ๊ฐ€ ๋‹ค๋ฅด๋‹ค โ€” ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ ์„ฑ๋Šฅ์€ CPU ์บ์‹œ ์นœํ™”๋„๊ฐ€ ๊ฒฐ์ •ํ•œ๋‹ค."

๋น„์œ  ์ •๋ฆฌ:

๋น„์œ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ•์ ์•ฝ์ 
์•„ํŒŒํŠธ ๋‹จ์ง€ArrayList์ธ๋ฑ์Šค ์ ‘๊ทผ (O(1))์ค‘๊ฐ„ ์‚ฝ์ž… (O(n))
๋ณด๋ฌผ์ฐพ๊ธฐ ์‚ฌ์ŠฌLinkedList์ค‘๊ฐ„ ์‚ฝ์ž… (O(1))์ธ๋ฑ์Šค ์ ‘๊ทผ (O(n))

โ†’ ๊ทธ๋Ÿฐ๋ฐ ํ˜„๋Œ€ CPU ์—์„œ๋Š” ArrayList ๊ฐ€ ๊ฑฐ์˜ ํ•ญ์ƒ ๋น ๋ฆ„ (์ด์œ ๋Š” ยง5์—์„œ).


๋˜ ๋‹ค๋ฅธ ๋น„์œ  โ€” "๋„์„œ๊ด€ ์ฑ…์žฅ"

ArrayList = ์ฑ…์žฅ์˜ ์ฑ…๋“ค:

  • ๋ชจ๋“  ์ฑ…์ด ์—ฐ์†ํ•ด์„œ ํ•œ ์ฑ…์žฅ์—
  • 5๋ฒˆ์งธ ์ฑ… = ์‹œ์ž‘์—์„œ 5๋ฒˆ์งธ (์ฆ‰์‹œ ์•Œ ์ˆ˜ ์žˆ์Œ)
  • ์ค‘๊ฐ„์— ์ƒˆ ์ฑ… ๋ผ์šฐ๋ ค๋ฉด โ†’ ๋’ค์˜ ๋ชจ๋“  ์ฑ…์„ ํ•œ ์นธ์”ฉ ๋ฐ€์–ด์•ผ

LinkedList = ํฉ์–ด์ง„ ์ฑ…๋“ค (ํŽธ์ง€๋กœ ์—ฐ๊ฒฐ):

  • ์ฑ…๋งˆ๋‹ค ๋‹ค์Œ ์ฑ…์˜ ์œ„์น˜ ๊ฐ€ ์ ํžŒ ํŽธ์ง€
  • 5๋ฒˆ์งธ ์ฑ… = 1โ†’2โ†’3โ†’4โ†’5 ๋”ฐ๋ผ๊ฐ€์•ผ
  • ์ค‘๊ฐ„์— ์ƒˆ ์ฑ…? โ†’ ํŽธ์ง€ ๋‘ ๊ฐœ๋งŒ ์ˆ˜์ •

๐Ÿ”ฅ 2. ํƒ„์ƒ ๋ฐฐ๊ฒฝ

"๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ €์žฅํ• ๊นŒ?" โ€” ๋‘ ๊ฐ€์ง€ ๋‹ต

๋ฐฐ์—ด๊ณผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” CS ์˜ ๊ฐ€์žฅ ๊ธฐ์ดˆ์ ์ธ ์ž๋ฃŒ๊ตฌ์กฐ.

๋ฐฐ์—ด (Array) โ€” 1950s

  • ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ ์— ๋ฐ์ดํ„ฐ ์ €์žฅ
  • ์ธ๋ฑ์Šค๋กœ ์ฆ‰์‹œ ์ ‘๊ทผ: array[i] = base_address + i * size
  • โ†’ O(1) ์ ‘๊ทผ
๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ: 1000  1004  1008  1012  1016
๋ฐ์ดํ„ฐ:      [10]  [20]  [30]  [40]  [50]
์ธ๋ฑ์Šค:        0     1     2     3     4

array[3] โ†’ 1000 + 3*4 = 1012 โ†’ ์ฆ‰์‹œ ์ ‘๊ทผ

๋ฌธ์ œ:

  • ๊ณ ์ • ํฌ๊ธฐ
  • ๊ฐ€๋“ ์ฐจ๋ฉด? โ†’ ์ƒˆ ๋ฐฐ์—ด ์ƒ์„ฑ + ๋ณต์‚ฌ
  • ์ค‘๊ฐ„ ์‚ฝ์ž…? โ†’ ๋’ค ์š”์†Œ ๋ชจ๋‘ ์ด๋™

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ (Linked List) โ€” 1960s

  • ํฉ์–ด์ง„ ๋ฉ”๋ชจ๋ฆฌ ์— ๋ฐ์ดํ„ฐ + ๋‹ค์Œ ์œ„์น˜ ํฌ์ธํ„ฐ
  • ์ธ๋ฑ์Šค ์ ‘๊ทผ X, ์ˆœ์ฐจ ํƒ์ƒ‰ ๋งŒ ๊ฐ€๋Šฅ
  • โ†’ O(n) ์ ‘๊ทผ
์ฃผ์†Œ 1000          ์ฃผ์†Œ 5000           ์ฃผ์†Œ 3000
[10][next=5000] โ†’ [20][next=3000] โ†’ [30][next=null]

์žฅ์ :

  • ๋™์  ํฌ๊ธฐ
  • ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ ๋น ๋ฆ„

๋‹จ์ :

  • ์ธ๋ฑ์Šค ์ ‘๊ทผ ๋А๋ฆผ
  • ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ (ํฌ์ธํ„ฐ)

์ž๋ฐ”์˜ ๋‹ต โ€” List ์ธํ„ฐํŽ˜์ด์Šค + ๋‘ ๊ตฌํ˜„์ฒด

์ž๋ฐ” 1.2 (1998) ์˜ ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›Œํฌ ๋Š” ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘ ์ œ๊ณต:

public interface List<E> extends Collection<E> {
    E get(int index);
    void add(E element);
    void add(int index, E element);
    E remove(int index);
    // ...
}

๊ตฌํ˜„ 1: ArrayList (๋ฐฐ์—ด ๊ธฐ๋ฐ˜)

public class ArrayList<E> implements List<E> {
    transient Object[] elementData;  // ๋‚ด๋ถ€ ๋ฐฐ์—ด
    private int size;
}

๊ตฌํ˜„ 2: LinkedList (์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ๊ธฐ๋ฐ˜)

public class LinkedList<E> implements List<E> {
    transient Node<E> first;  // ์ฒซ ๋…ธ๋“œ
    transient Node<E> last;   // ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ
    transient int size;
    
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
    }
}

โ†’ ๊ฐ™์€ List ์ธํ„ฐํŽ˜์ด์Šค, ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋‚ด๋ถ€ ๊ตฌ์กฐ.


์‹œ๊ฐ„ ๋ณต์žก๋„ ๋น„๊ต

์—ฐ์‚ฐArrayListLinkedList
get(i)O(1) โญO(n)
add(e) (๋)O(1) amortizedO(1) โญ
add(0, e) (์•ž)O(n)O(1) โญ
add(i, e) (์ค‘๊ฐ„)O(n)O(n) ํƒ์ƒ‰ + O(1) ์‚ฝ์ž…
remove(i)O(n)O(n) (ํƒ์ƒ‰์ด ๋น„์Œˆ)
contains(e)O(n)O(n)
size()O(1)O(1)

Big-O ๋งŒ ๋ณด๋ฉด:

  • ์ธ๋ฑ์Šค ์ ‘๊ทผ โ†’ ArrayList ์••๋„์ 
  • ์ค‘๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ โ†’ ๋น„์Šท (LinkedList ๊ฐ€ ์•ฝ๊ฐ„ ์œ ๋ฆฌ?)

๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ๋Š” โ€” ArrayList ๊ฐ€ ๊ฑฐ์˜ ํ•ญ์ƒ ๋น ๋ฆ„

"์ด๋ก ๊ณผ ์‹ค๋ฌด์˜ ๊ดด๋ฆฌ โ€” CPU ์บ์‹œ ์นœํ™”๋„."

LinkedList ์˜ ๋ชจ๋“  ๋…ธ๋“œ๋Š” Heap ์˜ ํฉ์–ด์ง„ ์œ„์น˜:

  • ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ 1000: Node A
  • ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ 7300: Node B (์ „ํ˜€ ๋‹ค๋ฅธ ๊ณณ)
  • ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ 4200: Node C

CPU ์บ์‹œ ๋ผ์ธ (๋ณดํ†ต 64 ๋ฐ”์ดํŠธ):

  • ๋ฉ”๋ชจ๋ฆฌ ํ•œ ๋ฒˆ ์ฝ์„ ๋•Œ โ†’ 64 ๋ฐ”์ดํŠธ ๋ฌถ์Œ
  • ArrayList: ํ•œ ๋ฒˆ ์ฝ์œผ๋ฉด ๋‹ค์Œ 16๊ฐœ (4 ๋ฐ”์ดํŠธ int) ๊ฐ€ ์บ์‹œ์—
  • LinkedList: ํ•œ ๋ฒˆ ์ฝ์œผ๋ฉด ๊ทธ ๋…ธ๋“œ๋งŒ, ๋‹ค์Œ์€ ๋˜ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ

๊ฒฐ๊ณผ:

  • ArrayList: L1 ์บ์‹œ ํžˆํŠธ โ†’ 1 ns
  • LinkedList: ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ โ†’ 100 ns (L1 ์˜ 100๋ฐฐ)

โ†’ ์ˆœ์ฐจ ์ฒ˜๋ฆฌ ์‹œ LinkedList ๊ฐ€ 100๋ฐฐ ๋А๋ฆด ์ˆ˜ ์žˆ์Œ.


ํ•ต์‹ฌ ํ†ต์ฐฐ

"Big-O ๋Š” ์‹œ์ž‘์ด์ง€ ๋์ด ์•„๋‹ˆ๋‹ค."

์ž๋ฃŒ๊ตฌ์กฐ ์„ ํƒ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„ + ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ ๋™์ž‘ + ์‚ฌ์šฉ ํŒจํ„ด ์˜ ์ข…ํ•ฉ. ArrayList ๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ์‹ค๋ฌด์—์„œ ์ •๋‹ต. LinkedList ๋Š” ๋งค์šฐ ํŠน์ •ํ•œ ์ƒํ™ฉ์—์„œ๋งŒ ์˜๋ฏธ. ์ด ์‚ฌ์‹ค์„ ์•„๋Š” ๊ฒƒ์ด ์‹œ๋‹ˆ์–ด ์ฐจ๋ณ„ํ™” ํฌ์ธํŠธ.


๐Ÿ’ฃ 3. ์—†์œผ๋ฉด ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ

์‹œ๋‚˜๋ฆฌ์˜ค 1: ILIC ์˜ ํ™”๋ฌผ ๋ชฉ๋ก ์ฒ˜๋ฆฌ

@Service
public class CargoService {
    
    public List<Cargo> processCargos(BookingRequest request) {
        // โŒ "์‚ฝ์ž… ๋งŽ์œผ๋‹ˆ๊นŒ LinkedList!" โ€” ํ”ํ•œ ์˜คํ•ด
        List<Cargo> cargos = new LinkedList<>();
        
        // 1๋งŒ ๊ฐœ ํ™”๋ฌผ ์ถ”๊ฐ€
        for (CargoData data : request.getCargoDataList()) {
            cargos.add(parseCargo(data));  // ๋์— ์ถ”๊ฐ€
        }
        
        // ์ฒ˜๋ฆฌ
        for (Cargo cargo : cargos) {
            processCargo(cargo);  // ์ˆœ์ฐจ ์ฒ˜๋ฆฌ
        }
        
        return cargos;
    }
}

๋ฌธ์ œ:

  • ์ถ”๊ฐ€๋Š” ๋‘˜ ๋‹ค O(1) (๋์— ์ถ”๊ฐ€)
  • ์ˆœ์ฐจ ์ฒ˜๋ฆฌ ์—์„œ LinkedList ๊ฐ€ ArrayList ๋ณด๋‹ค 5~10๋ฐฐ ๋А๋ฆผ (์บ์‹œ ๋ฏธ์Šค)
  • ILIC API ์‘๋‹ต ์‹œ๊ฐ„ โ†‘

ํ•ด๊ฒฐ:

List<Cargo> cargos = new ArrayList<>();  // ๊ฑฐ์˜ ํ•ญ์ƒ ์ •๋‹ต

์‹œ๋‚˜๋ฆฌ์˜ค 2: ๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ

Q: "ArrayList ์™€ LinkedList ์˜ ์ฐจ์ด๋Š”?"
A: "ArrayList ๋Š” ๋ฐฐ์—ด ๊ธฐ๋ฐ˜, LinkedList ๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ ๊ธฐ๋ฐ˜์ด์—์š”"  โญ• ๊ธฐ์ดˆ

์‹œ๋‹ˆ์–ด ๋‹ต๋ณ€:

  • ์‹œ๊ฐ„ ๋ณต์žก๋„ ์ฐจ์ด (O(1) vs O(n) ์ธ๋ฑ์Šค ์ ‘๊ทผ)
  • ๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ (LinkedList ๋…ธ๋“œ์˜ prev/next ํฌ์ธํ„ฐ)
  • CPU ์บ์‹œ ์นœํ™”๋„ (ArrayList ๊ฐ€ ์บ์‹œ ํžˆํŠธ์œจ ๋†’์Œ)
  • ์‹ค๋ฌด ๊ถŒ์žฅ: ๊ฑฐ์˜ ํ•ญ์ƒ ArrayList
  • LinkedList ์˜ ์ง„์งœ ์‚ฌ์šฉ์ฒ˜: Deque (์–‘๋ฐฉํ–ฅ ํ), ํ•œ์ •๋œ ๊ฒฝ์šฐ๋งŒ

์‹œ๋‚˜๋ฆฌ์˜ค 3: ์ž˜๋ชป๋œ ์ธ๋ฑ์Šค ์ ‘๊ทผ

// โŒ LinkedList ์— ์ธ๋ฑ์Šค ๋ฐ˜๋ณต ์ ‘๊ทผ
List<Booking> bookings = new LinkedList<>(loadBookings());

for (int i = 0; i < bookings.size(); i++) {
    Booking b = bookings.get(i);  // โš ๏ธ ๋งค๋ฒˆ O(n) ํƒ์ƒ‰!
    process(b);
}

// ์‹œ๊ฐ„ ๋ณต์žก๋„: O(nยฒ)
// 1๋งŒ ๊ฐœ โ†’ 1์–ต ๋ฒˆ ๋น„๊ต

๋ฌธ์ œ:

  • get(i) ๊ฐ€ LinkedList ์—์„œ๋Š” O(n) ํƒ์ƒ‰
  • ๋ฐ˜๋ณต๋ฌธ ๋‚ด๋ถ€ โ†’ O(nยฒ) ์‹œ๊ฐ„ ๋ณต์žก๋„
  • 1๋งŒ ๊ฐœ์—์„œ ์ˆ˜ ๋ถ„ ๊ฑธ๋ฆผ

ํ•ด๊ฒฐ 1: ArrayList

List<Booking> bookings = new ArrayList<>(loadBookings());
for (int i = 0; i < bookings.size(); i++) {
    Booking b = bookings.get(i);  // O(1)
}
// O(n) ์‹œ๊ฐ„ ๋ณต์žก๋„

ํ•ด๊ฒฐ 2: Iterator (LinkedList ๋ผ๋„)

List<Booking> bookings = ...;  // ์–ด๋–ค List ๋“ 
for (Booking b : bookings) {  // ํ–ฅ์ƒ๋œ for = Iterator
    process(b);
}
// LinkedList ์—์„œ๋„ O(n)

์‹œ๋‚˜๋ฆฌ์˜ค 4: ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ถฉ๊ฒฉ

// 100๋งŒ ๊ฐœ Integer ์ €์žฅ
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();

for (int i = 0; i < 1_000_000; i++) {
    arrayList.add(i);
    linkedList.add(i);
}

๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ธก์ •:

  • ArrayList: ~16MB (Integer ๊ฐ์ฒด + ๋ฐฐ์—ด)
  • LinkedList: ~48MB (3๋ฐฐ!)

์™œ 3๋ฐฐ?:

  • ArrayList: ์ฐธ์กฐ 1๊ฐœ per ์š”์†Œ (4~8 ๋ฐ”์ดํŠธ)
  • LinkedList: Node ๊ฐ์ฒด + prev + next + item = 4๊ฐœ ์ฐธ์กฐ + ๊ฐ์ฒด ํ—ค๋” (16 + 24 = 40 ๋ฐ”์ดํŠธ)

๊ฒฐ๊ณผ:

  • ํฐ ๋ฐ์ดํ„ฐ์—์„œ LinkedList ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ• โ†’ GC ๋ถ€๋‹ด โ†‘

์‹œ๋‚˜๋ฆฌ์˜ค 5: ConcurrentModificationException

// โŒ ์ˆœํšŒ ์ค‘ ์ˆ˜์ •
List<Cargo> cargos = new ArrayList<>(allCargos);

for (Cargo c : cargos) {
    if (c.isExpired()) {
        cargos.remove(c);  // โš ๏ธ ConcurrentModificationException!
    }
}

๋ฌธ์ œ:

  • Iterator ๊ฐ€ modCount ๋ฅผ ์ถ”์ 
  • ์ˆœํšŒ ์ค‘ ์™ธ๋ถ€์—์„œ ์ˆ˜์ • โ†’ ์˜ˆ์™ธ ๋ฐœ์ƒ
  • ArrayList, LinkedList ๋‘˜ ๋‹ค ์ ์šฉ

ํ•ด๊ฒฐ 1: Iterator.remove()

Iterator<Cargo> iter = cargos.iterator();
while (iter.hasNext()) {
    if (iter.next().isExpired()) {
        iter.remove();  // โœ“ ์•ˆ์ „
    }
}

ํ•ด๊ฒฐ 2: Java 8 removeIf

cargos.removeIf(Cargo::isExpired);  // โœ“ ๊ฐ€์žฅ ๊น”๋”

ํ•ด๊ฒฐ 3: Stream

cargos = cargos.stream()
    .filter(c -> !c.isExpired())
    .collect(Collectors.toList());

์‹œ๋‚˜๋ฆฌ์˜ค 6: ILIC ์˜ ์‹ค์‹œ๊ฐ„ ํ™”๋ฌผ ์œ„์น˜ ์ถ”์ 

// ์‹œ๋‚˜๋ฆฌ์˜ค: ํ™”๋ฌผ 100๋งŒ ๊ฑด์˜ ์œ„์น˜ ์—…๋ฐ์ดํŠธ
public class CargoTrackingService {
    
    private List<CargoLocation> locations;  // ์–ด๋–ค List?
    
    public void updateLocation(int cargoId, Coordinate coord) {
        CargoLocation loc = locations.get(cargoId);  // O(?)
        loc.setCoordinate(coord);
    }
    
    public void addCargo(CargoLocation loc) {
        locations.add(loc);  // O(?)
    }
    
    public List<CargoLocation> getCargosNearby(Coordinate target) {
        // ์ˆœ์ฐจ ํƒ์ƒ‰
        return locations.stream()
            .filter(l -> distance(l, target) < 100)
            .collect(Collectors.toList());
    }
}

ArrayList ์„ ํƒ ์‹œ:

  • get(cargoId): O(1) โญ (์ž์ฃผ ํ˜ธ์ถœ๋˜๋Š” ์œ„์น˜ ์—…๋ฐ์ดํŠธ)
  • add(): O(1) amortized
  • ์ˆœ์ฐจ ํ•„ํ„ฐ: ์บ์‹œ ์นœํ™”์ 

LinkedList ์„ ํƒ ์‹œ:

  • get(cargoId): O(n) โ€” 100๋งŒ ๋ฒˆ ํƒ์ƒ‰! โš ๏ธ
  • 100๋งŒ ๊ฑด ์œ„์น˜ ์—…๋ฐ์ดํŠธ = O(nยฒ) = ์‚ฌ์‹ค์ƒ ๋ฉˆ์ถค

โ†’ ArrayList ์••๋„์  ์Šน.


์˜ํ–ฅ ์ •๋ฆฌ

์‹œ๋‚˜๋ฆฌ์˜คLinkedList ์ž˜๋ชป ์„ ํƒArrayList ์ •๋‹ต
ํ™”๋ฌผ ๋ชฉ๋ก ์ˆœ์ฐจ ์ฒ˜๋ฆฌ5~10๋ฐฐ ๋А๋ฆผ๋น ๋ฆ„
์ธ๋ฑ์Šค ์ ‘๊ทผ ๋ฐ˜๋ณตO(nยฒ)O(n)
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ3๋ฐฐ ์‚ฌ์šฉํšจ์œจ
์œ„์น˜ ์—…๋ฐ์ดํŠธ์‚ฌ์‹ค์ƒ ๋ฉˆ์ถค์ •์ƒ
๋ฉด์ ‘ ๋‹ต๋ณ€ํ‘œ๋ฉด์ ์‹œ๋‹ˆ์–ด

โ†’ ์ž๋ฃŒ๊ตฌ์กฐ ์„ ํƒ์€ ์‹œ๋‹ˆ์–ด ์ž๋ฐ” ๊ฐœ๋ฐœ์ž์˜ ํ•ต์‹ฌ ์—ญ๋Ÿ‰.


โœ… 4. ํ•ด๊ฒฐ์ฑ… โ€” ๋‘ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ •ํ™•ํ•œ ์ดํ•ด

ArrayList โ€” ํ‘œ์ค€ โญ

๊ธฐ๋ณธ ์‚ฌ์šฉ

List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");

System.out.println(list.get(1));  // "Banana"
System.out.println(list.size());   // 3

// ์ธ๋ฑ์Šค ๊ธฐ๋ฐ˜ ๋ฐ˜๋ณต
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

// ํ–ฅ์ƒ๋œ for (๊ถŒ์žฅ)
for (String fruit : list) {
    System.out.println(fruit);
}

์ฃผ์š” ๋ฉ”์„œ๋“œ์™€ ์‹œ๊ฐ„ ๋ณต์žก๋„

ArrayList<String> list = new ArrayList<>();

// === ์ถ”๊ฐ€ ===
list.add("A");                 // O(1) amortized
list.add(0, "Front");          // O(n) โ€” ๋ชจ๋“  ์š”์†Œ ์ด๋™
list.addAll(otherList);        // O(m)

// === ์กฐํšŒ ===
String s = list.get(0);        // O(1) โญ
int idx = list.indexOf("A");   // O(n)
boolean has = list.contains("A");  // O(n)

// === ์ˆ˜์ • ===
list.set(0, "X");              // O(1)

// === ์‚ญ์ œ ===
list.remove(0);                // O(n) โ€” ๋’ค ์š”์†Œ ์ด๋™
list.remove("A");              // O(n)
list.removeIf(s -> s.startsWith("X"));  // O(n)

// === ์ •๋ณด ===
list.size();                   // O(1)
list.isEmpty();                // O(1)
list.clear();                  // O(n)

// === ๋ณ€ํ™˜ ===
list.toArray();                // O(n)
list.subList(0, 2);            // O(1) view

์ดˆ๊ธฐ capacity ์„ค์ •

// โŒ ๊ธฐ๋ณธ capacity (10)
List<Cargo> cargos = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
    cargos.add(...);  // ์•ฝ 14๋ฒˆ ํ™•์žฅ ๋ฐœ์ƒ
}

// โœ“ ๋ฏธ๋ฆฌ ์„ค์ •
List<Cargo> cargos = new ArrayList<>(100000);
for (int i = 0; i < 100000; i++) {
    cargos.add(...);  // ํ™•์žฅ ์—†์Œ
}

ํšจ๊ณผ: 30~50% ์„ฑ๋Šฅ ํ–ฅ์ƒ (ํฐ ๋ฐ์ดํ„ฐ์ผ์ˆ˜๋ก ํผ).


LinkedList โ€” ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ๋งŒ

๊ธฐ๋ณธ ์‚ฌ์šฉ

LinkedList<String> list = new LinkedList<>();
list.add("A");
list.addFirst("Front");  // โ˜… ์•ž์— ์ถ”๊ฐ€
list.addLast("Last");    // โ˜… ๋์— ์ถ”๊ฐ€

// LinkedList ๋งŒ์˜ ๋ฉ”์„œ๋“œ
list.peekFirst();  // "Front"
list.peekLast();   // "Last"
list.pollFirst();  // "Front" ์ œ๊ฑฐ + ๋ฐ˜ํ™˜
list.pollLast();   // "Last" ์ œ๊ฑฐ + ๋ฐ˜ํ™˜

LinkedList ์˜ ์ง„์งœ ๊ฐ•์  โ€” Deque (์–‘๋ฐฉํ–ฅ ํ)

// LinkedList ๋Š” Deque ์ธํ„ฐํŽ˜์ด์Šค๋„ ๊ตฌํ˜„
Deque<String> deque = new LinkedList<>();

// ์Šคํƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ
deque.push("A");
deque.push("B");
deque.pop();  // "B"

// ํ์ฒ˜๋Ÿผ ์‚ฌ์šฉ
deque.offer("A");
deque.offer("B");
deque.poll();  // "A"

๊ทธ๋Ÿฌ๋‚˜: Deque ๊ฐ€ ํ•„์š”ํ•˜๋ฉด ArrayDeque ๊ฐ€ ๋” ์ข‹์Œ (์บ์‹œ ์นœํ™”).


LinkedList ๊ฐ€ ์˜๋ฏธ ์žˆ๋Š” ๊ฒฝ์šฐ (ํฌ๊ท€)

Case 1: ์–‘ ๋์—์„œ๋งŒ ๋นˆ๋ฒˆํ•œ ์‚ฝ์ž…/์‚ญ์ œ + ์ˆœ์ฐจ ์ ‘๊ทผ

// ์ž‘์—… ํ (FIFO) โ€” ๊ทธ๋Ÿฌ๋‚˜ ArrayDeque ๊ฐ€ ๋” ์ข‹์Œ
LinkedList<Task> queue = new LinkedList<>();
queue.offer(task);  // ๋์— ์ถ”๊ฐ€
queue.poll();       // ์•ž์—์„œ ์ œ๊ฑฐ

Case 2: ์‚ฝ์ž…/์‚ญ์ œ๋งŒ ๋งค์šฐ ๋นˆ๋ฒˆ + ์ธ๋ฑ์Šค ์ ‘๊ทผ X

// ๊ทธ๋Ÿฌ๋‚˜ ์‹ค๋ฌด์—์„œ ๊ฑฐ์˜ ์—†์Œ

โ†’ ํ˜„์‹ค์ ์œผ๋กœ LinkedList ์‚ฌ์šฉ์ฒ˜๋Š” ๊ฑฐ์˜ ์—†์Œ. ArrayList ๋˜๋Š” ArrayDeque ๊ฐ€ ํ•ญ์ƒ ๋” ์ข‹์Œ.


๋น„๊ต ํ‘œ โญโญ (๋ฉด์ ‘ ๋‹ต๋ณ€ ํ•ต์‹ฌ)

ํ•ญ๋ชฉArrayListLinkedList
๋‚ด๋ถ€ ๊ตฌ์กฐ๋™์  ๋ฐฐ์—ด์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ
์ธ๋ฑ์Šค ์ ‘๊ทผO(1) โญO(n)
๋ ์ถ”๊ฐ€O(1) amortizedO(1)
์•ž ์ถ”๊ฐ€O(n)O(1)
์ค‘๊ฐ„ ์ถ”๊ฐ€ (ํƒ์ƒ‰ ํ›„)O(n)O(n)
๋ฉ”๋ชจ๋ฆฌ/์š”์†Œ~8 ๋ฐ”์ดํŠธ~40 ๋ฐ”์ดํŠธ (5๋ฐฐ)
์บ์‹œ ์นœํ™”๋„๋†’์Œ โญ๋‚ฎ์Œ
์ˆœ์ฐจ ๋ฐ˜๋ณต๋น ๋ฆ„ โญ๋А๋ฆผ (5~10๋ฐฐ)
๊ถŒ์žฅ๋„๊ฑฐ์˜ ๋ชจ๋“  ๊ฒฝ์šฐ๋งค์šฐ ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ

์„ ํƒ ๊ฐ€์ด๋“œ โญ (์‹ค์šฉ)

List ๊ฐ€ ํ•„์š”ํ•˜๋‹ค โ†’ ArrayList โญ (90% ์ด์ƒ์˜ ๊ฒฝ์šฐ)
        โ†“
์ •๋ง ์–‘ ๋์—์„œ๋งŒ ๋นˆ๋ฒˆํ•œ ์‚ฝ์ž…?
โ”œโ”€โ”€ YES โ†’ ArrayDeque โญ (LinkedList ๋ณด๋‹ค ์ข‹์Œ)
โ””โ”€โ”€ NO  โ†’ ArrayList

๊ฒฐ๋ก : ์ž๋ฐ”์—์„œ LinkedList ๋Š” ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ.


Stream + List ํŒจํ„ด

// ์ž์ฃผ ์“ฐ๋Š” ํŒจํ„ด
List<Cargo> result = cargos.stream()
    .filter(c -> c.getWeight() > 100)
    .collect(Collectors.toList());  // ๊ธฐ๋ณธ ArrayList

// Java 16+ ์˜ toList()
List<Cargo> result = cargos.stream()
    .filter(c -> c.getWeight() > 100)
    .toList();  // ๋ถˆ๋ณ€ List

Collectors.toList() ์˜ ๊ฒฐ๊ณผ: ๊ธฐ๋ณธ์ ์œผ๋กœ ArrayList.


๋ถˆ๋ณ€ List

// Java 9+
List<String> immutable = List.of("A", "B", "C");

// ์‹œ๋„ ์‹œ UnsupportedOperationException
immutable.add("D");  // โŒ ์˜ˆ์™ธ

์šฉ๋„: ์ƒ์ˆ˜ ๋ฆฌ์ŠคํŠธ, ๋ถˆ๋ณ€์„ฑ ๋ณด์žฅ ํ•„์š” ์‹œ.


๐Ÿ—๏ธ 5. ๋‚ด๋ถ€ ๋™์ž‘ ์›๋ฆฌ

ArrayList ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ

public class ArrayList<E> {
    transient Object[] elementData;  // ๋‚ด๋ถ€ ๋ฐฐ์—ด
    private int size;                // ์‹ค์ œ ์‚ฌ์šฉ ์ค‘ ๊ฐœ์ˆ˜
    
    // ๊ธฐ๋ณธ capacity
    private static final int DEFAULT_CAPACITY = 10;
}

ํ•ต์‹ฌ:

  • elementData.length = capacity (๋ฐฐ์—ด ํฌ๊ธฐ)
  • size = ํ˜„์žฌ ์‚ฌ์šฉ ๊ฐœ์ˆ˜
  • size โ‰ค capacity

ArrayList.add() ์˜ ๋™์ž‘

public boolean add(E e) {
    modCount++;
    if (size == elementData.length) {
        elementData = grow();  // ํ™•์žฅ!
    }
    elementData[size] = e;
    size++;
    return true;
}

private Object[] grow() {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);  // 1.5๋ฐฐ
    return Arrays.copyOf(elementData, newCapacity);
}

ํ™•์žฅ ๊ณต์‹: newCapacity = oldCapacity * 1.5

์ดˆ๊ธฐ: 10
11๋ฒˆ์งธ ์ถ”๊ฐ€: 10 * 1.5 = 15
16๋ฒˆ์งธ ์ถ”๊ฐ€: 15 * 1.5 = 22
23๋ฒˆ์งธ ์ถ”๊ฐ€: 22 * 1.5 = 33
...

โ†’ ์ ์ง„์ ์œผ๋กœ ํฐ ํญ ํ™•์žฅ, amortized O(1).


ArrayList.get() ์˜ ๋™์ž‘

public E get(int index) {
    Objects.checkIndex(index, size);
    return (E) elementData[index];  // ๋ฐฐ์—ด ์ง์ ‘ ์ ‘๊ทผ
}

O(1): ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ์ง์ ‘ ๊ณ„์‚ฐ.


ArrayList.add(0, e) ์˜ ๋™์ž‘ (์•ž์— ์ถ”๊ฐ€)

public void add(int index, E element) {
    rangeCheckForAdd(index);
    modCount++;
    if (size == elementData.length) {
        elementData = grow();
    }
    
    // ๋’ค ์š”์†Œ๋ฅผ ํ•œ ์นธ์”ฉ ๋’ค๋กœ ์ด๋™
    System.arraycopy(elementData, index,
                     elementData, index + 1,
                     size - index);
    
    elementData[index] = element;
    size++;
}

O(n): arraycopy ๊ฐ€ ๋น ๋ฅด๊ธด ํ•˜์ง€๋งŒ n ์— ๋น„๋ก€.


ArrayList ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฆผ

elementData = [A][B][C][D][E][_][_][_][_][_]
              โ†‘                โ†‘              โ†‘
              0              size=5    capacity=10

JVM Heap:
  [ArrayList ๊ฐ์ฒด]
    size: 5
    elementData: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                              โ†“
  [Object[] ๋ฐฐ์—ด โ€” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ]
    [A][B][C][D][E][null][null][null][null][null]

ํ•ต์‹ฌ: ๋ฐฐ์—ด์€ ํ•˜๋‚˜์˜ ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ ๋ธ”๋ก.


LinkedList ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ

public class LinkedList<E> {
    transient int size = 0;
    transient Node<E> first;  // ์ฒซ ๋…ธ๋“œ
    transient Node<E> last;   // ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ
    
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;
        
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
}

ํ•ต์‹ฌ:

  • ๊ฐ ์š”์†Œ๊ฐ€ Node ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ์ง
  • prev + next ํฌ์ธํ„ฐ๋กœ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ฒฐ

LinkedList ์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฆผ

JVM Heap:
  [LinkedList ๊ฐ์ฒด]
    size: 5
    first: โ”€โ”€โ”
    last:  โ”€โ”€โ”ผโ”€โ”
              โ”‚ โ”‚
  [Node A]   โ”‚ โ”‚
    prev: null
    item: "A"
    next: โ”€โ”€โ†’[Node B]
              โ”‚ โ”‚       prev: โ”€โ”€โ†’[Node A]
              โ”‚ โ”‚       item: "B"
              โ”‚ โ”‚       next: โ”€โ”€โ†’[Node C]
              โ”‚ โ”‚
              โ”‚ โ”‚
              โ”‚ โ”‚     [Node E]
              โ”‚ โ””โ”€โ”€โ†’  prev: โ”€โ”€โ†’[Node D]
                       item: "E"
                       next: null

ํ•ต์‹ฌ:

  • Node ๊ฐ์ฒด๋“ค์ด Heap ์˜ ํฉ์–ด์ง„ ์œ„์น˜
  • ๊ฐ Node ๋งˆ๋‹ค ๊ฐ์ฒด ํ—ค๋” + 3๊ฐœ ์ฐธ์กฐ (prev, item, next)
  • 64๋น„ํŠธ JVM์—์„œ Node 1๊ฐœ โ‰ˆ 40 ๋ฐ”์ดํŠธ

LinkedList.get() ์˜ ๋™์ž‘ โ€” ํ•จ์ •

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

Node<E> node(int index) {
    if (index < (size >> 1)) {
        // ์•ž์ชฝ์ด๋ฉด first ๋ถ€ํ„ฐ
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;  // โ˜… ์ˆœ์ฐจ ํƒ์ƒ‰
        return x;
    } else {
        // ๋’ค์ชฝ์ด๋ฉด last ๋ถ€ํ„ฐ
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;  // โ˜… ์ˆœ์ฐจ ํƒ์ƒ‰
        return x;
    }
}

O(n/2) = O(n): ๊ทธ๋Ÿฌ๋‚˜ ์–‘๋ฐฉํ–ฅ ํƒ์ƒ‰์œผ๋กœ ์ ˆ๋ฐ˜์€ ์ ˆ์•ฝ.

โ†’ ์ธ๋ฑ์Šค ์ ‘๊ทผ์— LinkedList ์‚ฌ์šฉ ์ ˆ๋Œ€ X.


LinkedList.add() ์˜ ๋™์ž‘ (๋์— ์ถ”๊ฐ€)

public boolean add(E e) {
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);  // โ˜… Node ๊ฐ์ฒด ์ƒ์„ฑ!
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
}

O(1): ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์— ์ง์ ‘ ์—ฐ๊ฒฐ.

๊ทธ๋Ÿฌ๋‚˜:

  • ๋งค๋ฒˆ Node ๊ฐ์ฒด ์ƒ์„ฑ โ†’ GC ๋ถ€๋‹ด
  • ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๋น„์šฉ โ†’ ArrayList ๋ณด๋‹ค ๋А๋ฆด ์ˆ˜ ์žˆ์Œ

CPU ์บ์‹œ ์นœํ™”๋„ (์ด Unit ์˜ ํ•ต์‹ฌ) โญโญโญ

CPU ์บ์‹œ ๊ณ„์ธต

[CPU Core] โ†โ”€โ”€ 1 ns
   โ†‘
[L1 Cache] (์ˆ˜์‹ญ KB)
   โ†‘ โ”€โ”€ 5 ns
[L2 Cache] (์ˆ˜๋ฐฑ KB)
   โ†‘ โ”€โ”€ 15 ns
[L3 Cache] (์ˆ˜ MB)
   โ†‘ โ”€โ”€ 30 ns
[Main Memory (RAM)] โ”€โ”€ 100 ns
   โ†‘
[Disk] โ”€โ”€ 10ms

์บ์‹œ ๋ผ์ธ (cache line):

  • ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ (๋ณดํ†ต 64 ๋ฐ”์ดํŠธ)
  • 1 ๋ฐ”์ดํŠธ ์ฝ์–ด๋„ โ†’ 64 ๋ฐ”์ดํŠธ ๊ฐ€์ ธ์˜ด

ArrayList ์˜ ์บ์‹œ ์นœํ™”๋„

List<Integer> list = new ArrayList<>(...);
for (Integer i : list) {
    // i ์ฒ˜๋ฆฌ
}

๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฆผ:

๋ฐฐ์—ด (์—ฐ์†):
[I0][I1][I2][I3][I4][I5][I6][I7]...
 โ†‘โ”€โ”€โ”€ 64 ๋ฐ”์ดํŠธ ์บ์‹œ ๋ผ์ธ โ”€โ”€โ”€โ”€โ†‘

L1 ์บ์‹œ์— ํ•œ ๋ฒˆ ๋กœ๋“œ โ†’ 8๊ฐœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ (4 ๋ฐ”์ดํŠธ int ๊ธฐ์ค€)
โ†’ ํ‰๊ท  1 ns per ์š”์†Œ

์ด๋ก : 1๋งŒ ๊ฐœ ์ฒ˜๋ฆฌ ์‹œ ์•ฝ 0.01 ms.


LinkedList ์˜ ์บ์‹œ ์นœํ™”๋„ (์—†์Œ)

List<Integer> list = new LinkedList<>(...);
for (Integer i : list) {
    // i ์ฒ˜๋ฆฌ
}

๋ฉ”๋ชจ๋ฆฌ ๊ทธ๋ฆผ:

Node A (์ฃผ์†Œ 1000)
  โ†’ Node B (์ฃผ์†Œ 7300) โ€” ์บ์‹œ ๋ผ์ธ ๋‹ค๋ฆ„
    โ†’ Node C (์ฃผ์†Œ 4200) โ€” ๋˜ ๋‹ค๋ฆ„
      โ†’ Node D (์ฃผ์†Œ 12000) โ€” ๋˜ ๋‹ค๋ฆ„

๋งค ์š”์†Œ๋งˆ๋‹ค:

  • ์บ์‹œ ๋ฏธ์Šค
  • L1 โ†’ L2 โ†’ L3 โ†’ RAM ๊นŒ์ง€ ๊ฐ€์•ผ ํ•  ์ˆ˜๋„
  • ํ‰๊ท  30~100 ns

ํ˜„์‹ค: 1๋งŒ ๊ฐœ ์ฒ˜๋ฆฌ ์‹œ ์•ฝ 0.5 ms (50๋ฐฐ ๋А๋ฆผ).


์‹ค์ œ ์ธก์ • ๊ฒฐ๊ณผ

public class CacheTest {
    public static void main(String[] args) {
        int N = 10_000_000;
        List<Integer> arr = new ArrayList<>(N);
        List<Integer> linked = new LinkedList<>();
        
        for (int i = 0; i < N; i++) {
            arr.add(i);
            linked.add(i);
        }
        
        // ArrayList ์ˆœํšŒ
        long start = System.nanoTime();
        long sum1 = 0;
        for (Integer i : arr) sum1 += i;
        long arrTime = System.nanoTime() - start;
        
        // LinkedList ์ˆœํšŒ
        start = System.nanoTime();
        long sum2 = 0;
        for (Integer i : linked) sum2 += i;
        long linkedTime = System.nanoTime() - start;
        
        System.out.println("ArrayList:  " + arrTime / 1_000_000 + " ms");
        // ์•ฝ 30 ms
        
        System.out.println("LinkedList: " + linkedTime / 1_000_000 + " ms");
        // ์•ฝ 200 ms (7๋ฐฐ ๋А๋ฆผ)
    }
}

๊ฒฐ๊ณผ: 5~10๋ฐฐ ์ฐจ์ด (๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™” ์ •๋„์— ๋”ฐ๋ผ 30๋ฐฐ๊นŒ์ง€).


Big-O ๊ฐ€ ๊ฑฐ์ง“๋งํ•˜๋Š” ์ด์œ 

Big-O ์˜ ๊ฐ€์ •:

  • ๋ชจ๋“  ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ๊ฐ™์€ ๋น„์šฉ
  • ์‹ค์ œ๋กœ๋Š” L1 ์บ์‹œ 1ns vs RAM 100ns = 100๋ฐฐ ์ฐจ์ด

ํ˜„๋Œ€ CPU ์˜ ์ง„์‹ค:

  • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„ < ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ํŒจํ„ด
  • "์ƒ์ˆ˜ 100๋ฐฐ ์ฐจ์ด" ๋Š” ์ž‘์€ N ์—์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฐจ์ด๋ฅผ ์••๋„

modCount โ€” Fail-Fast Iterator

public class ArrayList<E> {
    protected transient int modCount = 0;
    
    public boolean add(E e) {
        modCount++;  // ์ˆ˜์ • ์‹œ ์ฆ๊ฐ€
        // ...
    }
    
    private class Itr implements Iterator<E> {
        int expectedModCount = modCount;
        
        public E next() {
            checkForComodification();
            // ...
        }
        
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}

Fail-Fast ์›์น™:

  • ์ˆœํšŒ ์ค‘ ์™ธ๋ถ€ ์ˆ˜์ • ๋ฐœ์ƒ โ†’ ์ฆ‰์‹œ ์˜ˆ์™ธ
  • ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ๋ณด์žฅ

๐Ÿ’ป 6. ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์‹œ

์˜ˆ์‹œ 1: ILIC ์˜ ํ™”๋ฌผ ๋ชฉ๋ก โ€” ArrayList

@Service
public class CargoService {
    
    public List<Cargo> getCargosByBooking(Long bookingId) {
        // โœ“ ArrayList โ€” ํ‘œ์ค€ ์„ ํƒ
        List<Cargo> cargos = new ArrayList<>();
        
        // DB ์—์„œ ํ™”๋ฌผ ๋กœ๋“œ
        try (PreparedStatement ps = conn.prepareStatement(
                "SELECT * FROM cargos WHERE booking_id = ?")) {
            ps.setLong(1, bookingId);
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    cargos.add(mapToCargo(rs));  // O(1)
                }
            }
        }
        
        return cargos;
    }
    
    public Cargo getCargoByIndex(List<Cargo> cargos, int index) {
        return cargos.get(index);  // O(1) โญ ArrayList ์˜ ๊ฐ•์ 
    }
    
    public List<Cargo> filterHeavy(List<Cargo> cargos, double minWeight) {
        // ์ˆœ์ฐจ ์ฒ˜๋ฆฌ โ€” ArrayList ์˜ ์บ์‹œ ์นœํ™”๋„ ํ™œ์šฉ
        return cargos.stream()
            .filter(c -> c.getWeight() >= minWeight)
            .collect(Collectors.toList());
    }
}

์˜ˆ์‹œ 2: ์ดˆ๊ธฐ capacity ์„ค์ •

@Service
public class BookingReportService {
    
    public List<BookingItem> generateMonthlyReport(int year, int month) {
        int estimatedSize = bookingRepository.countByMonth(year, month);
        
        // โœ“ ๋ฏธ๋ฆฌ capacity ์„ค์ •
        List<BookingItem> items = new ArrayList<>(estimatedSize);
        
        bookingRepository.streamByMonth(year, month)
            .forEach(b -> items.add(toBookingItem(b)));
        
        return items;
    }
}

ํšจ๊ณผ: ํฐ ๋ฐ์ดํ„ฐ์—์„œ 30~50% ์„ฑ๋Šฅ ํ–ฅ์ƒ.


์˜ˆ์‹œ 3: ์•ˆ์ „ํ•œ ์ˆœํšŒ + ์ˆ˜์ •

public class CargoFilterService {
    
    // โŒ ์œ„ํ—˜
    public void removeExpiredUnsafe(List<Cargo> cargos) {
        for (Cargo c : cargos) {
            if (c.isExpired()) {
                cargos.remove(c);  // ConcurrentModificationException!
            }
        }
    }
    
    // โœ“ Iterator
    public void removeExpiredIterator(List<Cargo> cargos) {
        Iterator<Cargo> iter = cargos.iterator();
        while (iter.hasNext()) {
            if (iter.next().isExpired()) {
                iter.remove();  // ์•ˆ์ „
            }
        }
    }
    
    // โœ“ removeIf (Java 8+)
    public void removeExpiredModern(List<Cargo> cargos) {
        cargos.removeIf(Cargo::isExpired);  // ๊ฐ€์žฅ ๊น”๋”
    }
    
    // โœ“ Stream (์ƒˆ List ์ƒ์„ฑ)
    public List<Cargo> filterAlive(List<Cargo> cargos) {
        return cargos.stream()
            .filter(c -> !c.isExpired())
            .collect(Collectors.toList());
    }
}

์˜ˆ์‹œ 4: ์–‘๋ฐฉํ–ฅ ํ โ€” ArrayDeque (LinkedList ๋Œ€์‹ )

@Service
public class TaskQueueService {
    
    // โŒ LinkedList ๋กœ ํ ๊ตฌํ˜„
    private LinkedList<Task> queue = new LinkedList<>();
    
    // โœ“ ArrayDeque โ€” ๋” ๋น ๋ฆ„!
    private ArrayDeque<Task> queue = new ArrayDeque<>();
    
    public void enqueue(Task task) {
        queue.offer(task);
    }
    
    public Task dequeue() {
        return queue.poll();
    }
}

์™œ ArrayDeque ๊ฐ€ ๋” ์ข‹์€๊ฐ€?:

  • ์›ํ˜• ๋ฐฐ์—ด ๊ธฐ๋ฐ˜
  • ์บ์‹œ ์นœํ™”๋„ โ†‘
  • LinkedList ๋ณด๋‹ค 2~3๋ฐฐ ๋น ๋ฆ„

์˜ˆ์‹œ 5: ILIC ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜

@Service
public class CargoSearchService {
    
    // โœ“ ArrayList โ€” ์ธ๋ฑ์Šค ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜
    public List<Cargo> getPage(int page, int pageSize) {
        List<Cargo> all = loadAll();  // ArrayList
        
        int from = page * pageSize;
        int to = Math.min(from + pageSize, all.size());
        
        // O(1) โ€” subList ๋Š” view
        return all.subList(from, to);
    }
}

LinkedList ๋ผ๋ฉด:

  • subList ๋„ ๋‚ด๋ถ€์ ์œผ๋กœ ์ธ๋ฑ์Šค ํƒ์ƒ‰ โ†’ O(n) ์ถ”๊ฐ€ ๋น„์šฉ
  • ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ๋А๋ ค์ง

์˜ˆ์‹œ 6: ์„ฑ๋Šฅ ๋น„๊ต ๋ฒค์น˜๋งˆํฌ

public class ListBenchmark {
    
    public static void main(String[] args) {
        int N = 1_000_000;
        
        // 1. ๋์— ์ถ”๊ฐ€
        long arrayListAdd = benchmark(() -> {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < N; i++) list.add(i);
        });
        
        long linkedListAdd = benchmark(() -> {
            List<Integer> list = new LinkedList<>();
            for (int i = 0; i < N; i++) list.add(i);
        });
        
        // 2. ์ˆœ์ฐจ ์ˆœํšŒ
        List<Integer> arr = new ArrayList<>(/* 1M items */);
        List<Integer> lnk = new LinkedList<>(/* 1M items */);
        
        long arrIter = benchmark(() -> {
            long sum = 0;
            for (Integer i : arr) sum += i;
        });
        
        long lnkIter = benchmark(() -> {
            long sum = 0;
            for (Integer i : lnk) sum += i;
        });
        
        // 3. ์ธ๋ฑ์Šค ์ ‘๊ทผ
        long arrGet = benchmark(() -> {
            for (int i = 0; i < N; i++) arr.get(i);
        });
        
        long lnkGet = benchmark(() -> {
            for (int i = 0; i < N; i++) lnk.get(i);  // โš ๏ธ O(nยฒ)
        });
        
        System.out.println("Add (end):");
        System.out.println("  ArrayList:  " + arrayListAdd + "ms");   // ~30ms
        System.out.println("  LinkedList: " + linkedListAdd + "ms");  // ~40ms
        
        System.out.println("Iterate:");
        System.out.println("  ArrayList:  " + arrIter + "ms");   // ~5ms
        System.out.println("  LinkedList: " + lnkIter + "ms");   // ~50ms (10๋ฐฐ)
        
        System.out.println("Get(i):");
        System.out.println("  ArrayList:  " + arrGet + "ms");    // ~10ms
        System.out.println("  LinkedList: " + lnkGet + "ms");    // ~์ˆ˜์‹ญ ๋ถ„ (์‚ฌ์‹ค์ƒ ๋ฉˆ์ถค)
    }
    
    static long benchmark(Runnable task) {
        long start = System.currentTimeMillis();
        task.run();
        return System.currentTimeMillis() - start;
    }
}

์˜ˆ์‹œ 7: ์ปฌ๋ ‰์…˜ ๋ณ€ํ™˜

public class CollectionConverter {
    
    // ๋ฐฐ์—ด โ†’ ArrayList
    Cargo[] array = ...;
    List<Cargo> list1 = new ArrayList<>(Arrays.asList(array));
    List<Cargo> list2 = Arrays.stream(array).collect(Collectors.toList());
    
    // List โ†’ ๋ฐฐ์—ด
    Cargo[] arr = list1.toArray(new Cargo[0]);
    
    // List โ†’ ๋‹ค๋ฅธ List
    List<Cargo> immutable = List.copyOf(list1);  // ๋ถˆ๋ณ€
    List<Cargo> sorted = list1.stream()
        .sorted(Comparator.comparing(Cargo::getWeight))
        .collect(Collectors.toList());
}

์˜ˆ์‹œ 8: ๋™์‹œ์„ฑ ์•ˆ์ „ List

public class ThreadSafeListExamples {
    
    // โŒ ์ผ๋ฐ˜ ArrayList โ€” ๋™์‹œ ์ˆ˜์ • ์‹œ ๋ฐ์ดํ„ฐ ์†์ƒ
    private List<Cargo> unsafeList = new ArrayList<>();
    
    // โœ“ 1. Collections.synchronizedList
    private List<Cargo> synced = Collections.synchronizedList(new ArrayList<>());
    // ๋ชจ๋“  ๋ฉ”์„œ๋“œ synchronized โ€” ๊ทธ๋Ÿฌ๋‚˜ ์ˆœํšŒ ์‹œ ์™ธ๋ถ€ ๋™๊ธฐํ™” ํ•„์š”!
    
    synchronized (synced) {
        for (Cargo c : synced) {  // ์ˆœํšŒ๋Š” ๋ช…์‹œ์  ๋™๊ธฐํ™”
            // ...
        }
    }
    
    // โœ“ 2. CopyOnWriteArrayList
    private List<Cargo> cow = new CopyOnWriteArrayList<>();
    // ์“ฐ๊ธฐ ์‹œ ์ „์ฒด ๋ณต์‚ฌ โ€” ์ฝ๊ธฐ ๋งŽ๊ณ  ์“ฐ๊ธฐ ์ ์€ ๊ฒฝ์šฐ
    
    // โœ“ 3. ConcurrentLinkedQueue (List ์•„๋‹˜)
    private Queue<Cargo> queue = new ConcurrentLinkedQueue<>();
    // ์ง„์ •ํ•œ ๋™์‹œ์„ฑ ํ
}

โš ๏ธ 7. ์ฃผ์˜์‚ฌํ•ญ & ํ”ํ•œ ์‹ค์ˆ˜

์‹ค์ˆ˜ 1: "์‚ฝ์ž… ๋งŽ์œผ๋‹ˆ๊นŒ LinkedList!"

// โŒ ํ”ํ•œ ์˜คํ•ด
List<Cargo> cargos = new LinkedList<>();
for (CargoData data : dataList) {
    cargos.add(parse(data));  // ๋์— ์ถ”๊ฐ€
}

์ง„์‹ค:

  • "๋์— ์ถ”๊ฐ€" ๋Š” ArrayList ๋„ O(1) amortized
  • LinkedList ๋Š” Node ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ + GC ๋ถ€๋‹ด
  • โ†’ ArrayList ๊ฐ€ ๋น ๋ฆ„

ํ•ด๊ฒฐ: ArrayList ๊ฐ€ ํ‘œ์ค€.


์‹ค์ˆ˜ 2: LinkedList ์— ์ธ๋ฑ์Šค ์ ‘๊ทผ

// โŒ ์น˜๋ช…์ 
LinkedList<Booking> list = ...;
for (int i = 0; i < list.size(); i++) {
    process(list.get(i));  // O(nยฒ)!
}

// 1๋งŒ ๊ฐœ โ†’ 1์–ต ๋ฒˆ ๋น„๊ต โ†’ ๋ถ„ ๋‹จ์œ„

ํ•ด๊ฒฐ: ํ–ฅ์ƒ๋œ for (Iterator ์‚ฌ์šฉ)

for (Booking b : list) {  // O(n)
    process(b);
}

์‹ค์ˆ˜ 3: ArrayList ์˜ ์•ž์— ๋นˆ๋ฒˆํ•œ ์ถ”๊ฐ€

// โŒ ๋น„ํšจ์œจ
List<Cargo> cargos = new ArrayList<>();
for (Cargo c : newCargos) {
    cargos.add(0, c);  // O(n) โ€” ๋ชจ๋“  ์š”์†Œ ์ด๋™
}

// 1๋งŒ ๊ฐœ โ†’ O(nยฒ)

ํ•ด๊ฒฐ 1: ๋์— ์ถ”๊ฐ€ ํ›„ reverse

for (Cargo c : newCargos) {
    cargos.add(c);
}
Collections.reverse(cargos);  // O(n)

ํ•ด๊ฒฐ 2: ArrayDeque

Deque<Cargo> deque = new ArrayDeque<>();
for (Cargo c : newCargos) {
    deque.offerFirst(c);  // O(1)
}

์‹ค์ˆ˜ 4: ConcurrentModificationException

// โŒ ์ˆœํšŒ ์ค‘ ์ˆ˜์ •
for (Cargo c : cargos) {
    if (c.isExpired()) {
        cargos.remove(c);  // ์˜ˆ์™ธ!
    }
}

ํ•ด๊ฒฐ: removeIf

cargos.removeIf(Cargo::isExpired);  // ๊ฐ€์žฅ ๊น”๋”

์‹ค์ˆ˜ 5: subList ์˜ ํ•จ์ •

List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));
List<Integer> sub = list.subList(1, 4);  // [2, 3, 4]

// subList ๋Š” view!
sub.add(99);  
// โ†’ list ๋„ ๋ณ€ํ•จ: [1, 2, 3, 4, 99, 5]

// ์›๋ณธ์„ ์ˆ˜์ •ํ•˜๋ฉด?
list.add(0, 100);
sub.size();  // ConcurrentModificationException!

ํ•ด๊ฒฐ: ์ƒˆ List ์ƒ์„ฑ

List<Integer> sub = new ArrayList<>(list.subList(1, 4));  // ๋ณต์‚ฌ

์‹ค์ˆ˜ 6: capacity ๋ฏธ์„ค์ •

// โŒ ํฐ ๋ฐ์ดํ„ฐ์ธ๋ฐ ๊ธฐ๋ณธ capacity (10)
List<Item> items = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
    items.add(...);  // ์•ฝ 30๋ฒˆ ํ™•์žฅ ๋ฐœ์ƒ
}

ํ•ด๊ฒฐ: ๋ฏธ๋ฆฌ ์„ค์ •

List<Item> items = new ArrayList<>(1_000_000);

์‹ค์ˆ˜ 7: List.of() ์ˆ˜์ • ์‹œ๋„

List<String> list = List.of("A", "B", "C");
list.add("D");  // โŒ UnsupportedOperationException

// List.of() ๋Š” ๋ถˆ๋ณ€!

ํ•ด๊ฒฐ: ๊ฐ€๋ณ€์ด ํ•„์š”ํ•˜๋ฉด

List<String> list = new ArrayList<>(List.of("A", "B", "C"));
list.add("D");  // โœ“

์‹ค์ˆ˜ 8: equals ์™€ hashCode

List<Cargo> list1 = new ArrayList<>(...);
List<Cargo> list2 = new LinkedList<>(...);

// ๋‘ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ฐ™์€ ์š”์†Œ๋ฉด?
list1.equals(list2);  // true (๊ตฌํ˜„ ๋‹ค๋ฅด์ง€๋งŒ ๋‚ด์šฉ ๊ฐ™์œผ๋ฉด)

// HashMap ํ‚ค๋กœ ์‚ฌ์šฉ ์‹œ?
Map<List<Cargo>, String> map = new HashMap<>();
map.put(list1, "value");

// ๊ทธ๋Ÿฌ๋‚˜ List ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด?
list1.add(new Cargo(...));
map.get(list1);  // null! (hashCode ๋ณ€๊ฒฝ๋จ)

์›์น™: ๊ฐ€๋ณ€ List ๋ฅผ HashMap ํ‚ค๋กœ ์‚ฌ์šฉ X.


๐Ÿ”— 8. ์—ฐ๊ด€ ๊ฐœ๋… ๋งต

Phase 6 (๋ฐ์ดํ„ฐ ๋‹ค๋ฃจ๊ธฐ) ์—์„œ์˜ ์œ„์น˜

[Unit 6.1: String + Constant Pool] โœ“
        โ†“
[Unit 6.2: StringBuilder vs StringBuffer] โœ“
        โ†“
[Unit 6.3: ArrayList vs LinkedList] โ† ์ง€๊ธˆ ์—ฌ๊ธฐ โ˜…
        โ†“
[Unit 6.4: HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ] โ˜…โ˜…โ˜… (๋‹ค์Œ, ํ•ต์‹ฌ)
        โ†“
[Unit 6.5: TreeMap, LinkedHashMap]

Phase 4-5 ์™€์˜ ์—ฐ๊ฒฐ

Phase์—ฐ๊ฒฐ
4.1 (JVM ๋ฉ”๋ชจ๋ฆฌ)๋ฐฐ์—ด์€ Heap ์— ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ
5.1 (GC)LinkedList ์˜ Node ๋“ค์ด GC ๋ถ€๋‹ด
5.2 (Heap ๊ตฌ์กฐ)ํฐ List ๋Š” Old Gen ์œผ๋กœ promotion

์ž๋ฐ” ์ปฌ๋ ‰์…˜ ํ”„๋ ˆ์ž„์›Œํฌ ์ „์ฒด

Collection (์ธํ„ฐํŽ˜์ด์Šค)
โ”œโ”€โ”€ List
โ”‚   โ”œโ”€โ”€ ArrayList โญ
โ”‚   โ”œโ”€โ”€ LinkedList
โ”‚   โ””โ”€โ”€ Vector (legacy, synchronized)
โ”‚
โ”œโ”€โ”€ Set
โ”‚   โ”œโ”€โ”€ HashSet
โ”‚   โ”œโ”€โ”€ LinkedHashSet
โ”‚   โ””โ”€โ”€ TreeSet
โ”‚
โ””โ”€โ”€ Queue / Deque
    โ”œโ”€โ”€ ArrayDeque โญ
    โ”œโ”€โ”€ LinkedList (Deque ๋„ ๊ตฌํ˜„)
    โ””โ”€โ”€ PriorityQueue

Map (๋ณ„๋„ ์ธํ„ฐํŽ˜์ด์Šค)
โ”œโ”€โ”€ HashMap โญ (Unit 6.4)
โ”œโ”€โ”€ LinkedHashMap (Unit 6.5)
โ”œโ”€โ”€ TreeMap (Unit 6.5)
โ””โ”€โ”€ ConcurrentHashMap

์‹œ๊ฐ„ ๋ณต์žก๋„ ์ข…ํ•ฉ

์ž๋ฃŒ๊ตฌ์กฐgetaddremovecontains
ArrayListO(1)O(1)*O(n)O(n)
LinkedListO(n)O(1)*O(n)O(n)
HashSet-O(1)O(1)O(1)
TreeSet-O(log n)O(log n)O(log n)
HashMap-O(1)O(1)O(1)
TreeMap-O(log n)O(log n)O(log n)

*amortized


๋‹ค๋ฅธ ์–ธ์–ด ๋น„๊ต

์–ธ์–ด๋™์  ๋ฐฐ์—ด์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ
JavaArrayListLinkedList
C++std::vectorstd::list
Pythonlist(์—†์Œ, deque)
JavaScriptArray(์—†์Œ)
C#List<T>LinkedList<T>
RustVec<T>LinkedList<T>

โ†’ ๊ฑฐ์˜ ๋ชจ๋“  ์–ธ์–ด๊ฐ€ ๋™์  ๋ฐฐ์—ด ํ‘œ์ค€ + ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ์˜ต์…˜.


๋ฉด์ ‘ ๋‹จ๊ณจ ์งˆ๋ฌธ ๋งคํ•‘

์งˆ๋ฌธ์ด Unit ์—์„œ์˜ ๋‹ต
ArrayList vs LinkedList?์‹œ๊ฐ„ ๋ณต์žก๋„ + CPU ์บ์‹œ
์–ธ์ œ LinkedList?๊ฑฐ์˜ ์—†์Œ (ArrayDeque ๊ฐ€ ๋ณดํ†ต ๋” ์ข‹์Œ)
ArrayList capacity ๋™์ž‘?1.5๋ฐฐ ํ™•์žฅ
์ธ๋ฑ์Šค ์ ‘๊ทผ ์ฐจ์ด?O(1) vs O(n)
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ?LinkedList ๊ฐ€ 5๋ฐฐ

๐Ÿ“ 9. ํ•ต์‹ฌ ์š”์•ฝ โ€” 3์ค„ ์ •๋ฆฌ

1๏ธโƒฃ ArrayList = ๋™์  ๋ฐฐ์—ด, LinkedList = ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ.

ArrayList ๋Š” ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ ์— ๋ฐฐ์—ด ๋ณด๊ด€ โ€” ์ธ๋ฑ์Šค ์ ‘๊ทผ O(1), ์ค‘๊ฐ„ ์‚ฝ์ž… O(n). LinkedList ๋Š” Node ๊ฐ์ฒด๋“ค์˜ ์–‘๋ฐฉํ–ฅ ์‚ฌ์Šฌ โ€” ์ธ๋ฑ์Šค ์ ‘๊ทผ O(n), ์ค‘๊ฐ„ ์‚ฝ์ž… O(1) (ํƒ์ƒ‰ ํ›„). Big-O ๋งŒ ๋ณด๋ฉด LinkedList ๊ฐ€ ์ข‹์•„ ๋ณด์ผ ์ˆ˜๋„ ์žˆ์œผ๋‚˜...

2๏ธโƒฃ CPU ์บ์‹œ ์นœํ™”๋„๊ฐ€ ๋ชจ๋“  ๊ฒƒ์„ ๋ฐ”๊พผ๋‹ค โ€” ArrayList ๊ฐ€ ๊ฑฐ์˜ ํ•ญ์ƒ ๋น ๋ฆ„.

ํ˜„๋Œ€ CPU ์˜ L1 ์บ์‹œ (1ns) vs RAM (100ns) ์˜ 100๋ฐฐ ์ฐจ์ด. ArrayList ๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ โ†’ ์บ์‹œ ๋ผ์ธ ํ™œ์šฉ โ†’ ๋‹ค์Œ ์š”์†Œ๊ฐ€ ์ด๋ฏธ ์บ์‹œ์—. LinkedList ๋Š” ํฉ์–ด์ง„ Node โ†’ ๋งค๋ฒˆ ์บ์‹œ ๋ฏธ์Šค โ†’ 100๋ฐฐ ๋А๋ฆผ. ์ˆœ์ฐจ ์ˆœํšŒ์—์„œ ArrayList ๊ฐ€ 5~10๋ฐฐ ๋น ๋ฆ„. ๋ฉ”๋ชจ๋ฆฌ๋„ 5๋ฐฐ ์ ๊ฒŒ ์‚ฌ์šฉ.

3๏ธโƒฃ ์‹ค๋ฌด ์›์น™ โ€” ArrayList ๊ฐ€ ํ‘œ์ค€, LinkedList ๋Š” ๊ฑฐ์˜ ์•ˆ ์”€.

List ๊ฐ€ ํ•„์š”ํ•˜๋ฉด ๋ฌด์กฐ๊ฑด ArrayList. ํฐ ๋ฐ์ดํ„ฐ๋ฉด new ArrayList<>(์˜ˆ์ƒํฌ๊ธฐ) ๋กœ capacity ๋ฏธ๋ฆฌ ์„ค์ •. ์–‘ ๋ ํ๊ฐ€ ํ•„์š”ํ•˜๋ฉด ArrayDeque (LinkedList ๋ณด๋‹ค ์ข‹์Œ). ์ˆœํšŒ ์ค‘ ์ˆ˜์ • ์€ removeIf ๋˜๋Š” Iterator.remove. HashMap ํ‚ค๋กœ ๊ฐ€๋ณ€ List ์‚ฌ์šฉ X (hashCode ๋ณ€๊ฒฝ ์œ„ํ—˜). LinkedList ๋Š” ๋ฉด์ ‘ ๋‹ต๋ณ€ ์™ธ์—๋Š” ์‚ฌ์šฉ์ฒ˜๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค๊ณ  ๋ด๋„ ๋ฌด๋ฐฉ.


๐ŸŽ“ ํ•™์Šต ์ž๊ธฐ ์ ๊ฒ€

๊ธฐ๋ณธ ์ดํ•ด

  • ArrayList ์™€ LinkedList ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋‹ค
  • ์‹œ๊ฐ„ ๋ณต์žก๋„ ์ฐจ์ด๋ฅผ ์ •ํ™•ํžˆ ์•ˆ๋‹ค (get, add, remove)
  • CPU ์บ์‹œ ์นœํ™”๋„๊ฐ€ ์™œ ์ค‘์š”ํ•œ์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค
  • ArrayList ์˜ 1.5๋ฐฐ ํ™•์žฅ์„ ์•ˆ๋‹ค

์‹ค์ „ ์ ์šฉ

  • ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒฝ์šฐ์— ArrayList ๋ฅผ ์„ ํƒํ•œ๋‹ค
  • ํฐ ๋ฐ์ดํ„ฐ ์‹œ capacity ๋ฅผ ๋ฏธ๋ฆฌ ์„ค์ •ํ•œ๋‹ค
  • ์–‘ ๋ ํ๋Š” ArrayDeque ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
  • ConcurrentModificationException ์„ ํšŒํ”ผํ•œ๋‹ค (removeIf)

๋ฉด์ ‘ ๋Œ€๋น„ (5๋ถ„ ๋‹ต๋ณ€)

  • "ArrayList vs LinkedList ์ฐจ์ด?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "Big-O ๋งŒ ๋ณด๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ ?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ
  • "์–ธ์ œ LinkedList?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ (๊ฑฐ์˜ ์—†์Œ)
  • "๋ฉ”๋ชจ๋ฆฌ ์ฐจ์ด?" ๋‹ต๋ณ€ ๊ฐ€๋Šฅ (5๋ฐฐ)

์ž๊ธฐ ์ ๊ฒ€ ์งˆ๋ฌธ ๋‹ต๋ณ€

Q1: ArrayList ๊ฐ€ LinkedList ๋ณด๋‹ค ๊ฑฐ์˜ ํ•ญ์ƒ ๋น ๋ฅธ ์ด์œ ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ + CPU ๊ด€์ ์—์„œ ์„ค๋ช…ํ•˜๋ผ.

ํ•œ ์ค„ ๋‹ต: ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๊ฐ€ CPU ์บ์‹œ ๋ผ์ธ ์„ ํšจ์œจ์ ์œผ๋กœ ํ™œ์šฉํ•ด L1 ์บ์‹œ (1ns) ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ. LinkedList ๋Š” ํฉ์–ด์ง„ Node ๋กœ ๋งค๋ฒˆ RAM (100ns) ์ ‘๊ทผ.

์ƒ์„ธ ์„ค๋ช…:

1. ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜ ์ฐจ์ด

ArrayList ์˜ ๋ฉ”๋ชจ๋ฆฌ:

Heap ์˜ ํ•œ ์˜์—ญ (์—ฐ์†):
์ฃผ์†Œ 1000: [Item 0]
์ฃผ์†Œ 1004: [Item 1]
์ฃผ์†Œ 1008: [Item 2]
์ฃผ์†Œ 1012: [Item 3]
...

LinkedList ์˜ ๋ฉ”๋ชจ๋ฆฌ:

Heap ์˜ ํฉ์–ด์ง„ ์˜์—ญ:
์ฃผ์†Œ 1000: [Node 0: prev=null, next=์ฃผ์†Œ 7300, item]
์ฃผ์†Œ 7300: [Node 1: prev=์ฃผ์†Œ 1000, next=์ฃผ์†Œ 4200, item]
์ฃผ์†Œ 4200: [Node 2: prev=์ฃผ์†Œ 7300, next=์ฃผ์†Œ 12000, item]
์ฃผ์†Œ 12000: [Node 3: ...]

์™œ ํฉ์–ด์ง€๋‚˜?:

  • LinkedList ์˜ Node ๋Š” ๊ฐ๊ฐ ๋ณ„๋„ new ๋กœ ์ƒ์„ฑ
  • JVM ์˜ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ž๊ฐ€ ๊ทธ๋•Œ๊ทธ๋•Œ ๋นˆ ๊ณต๊ฐ„์— ๋ฐฐ์น˜
  • โ†’ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์ƒ ์ธ์ ‘ X

2. CPU ์บ์‹œ ๊ณ„์ธต์˜ ๋น„์šฉ

L1 Cache (32 KB):    ~ 1 ns   (CPU ์ฝ”์–ด ์˜†)
L2 Cache (256 KB):   ~ 5 ns
L3 Cache (8 MB):     ~ 30 ns  (์ฝ”์–ด ๊ณต์œ )
RAM (16 GB):         ~ 100 ns

ํ•ต์‹ฌ: L1 vs RAM = 100๋ฐฐ ์ฐจ์ด.


3. ์บ์‹œ ๋ผ์ธ (Cache Line)

CPU ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ฝ์„ ๋•Œ:

  • 64 ๋ฐ”์ดํŠธ ๋ฌถ์Œ ์œผ๋กœ ๊ฐ€์ ธ์˜ด (์บ์‹œ ๋ผ์ธ ๋‹จ์œ„)
  • 1 ๋ฐ”์ดํŠธ๋งŒ ํ•„์š”ํ•ด๋„ 64 ๋ฐ”์ดํŠธ ๊ฐ€์ ธ์˜ด
  • โ†’ "๊ทผ์ฒ˜ ๋ฐ์ดํ„ฐ" ๊ฐ€ ๊ฐ™์ด ๋“ค์–ด์˜ด

ArrayList ์˜ ํ™œ์šฉ:

๋ฐฐ์—ด: [I0][I1][I2][I3][I4][I5][I6][I7]...
       โ†‘โ”€โ”€โ”€ 64 ๋ฐ”์ดํŠธ ์บ์‹œ ๋ผ์ธ โ”€โ”€โ”€โ”€โ†‘

์ฒ˜๋ฆฌ:
1. I0 ์ฝ๊ธฐ โ†’ ์บ์‹œ ๋ฏธ์Šค โ†’ 64 ๋ฐ”์ดํŠธ ๊ฐ€์ ธ์˜ด (I0~I15)
2. I1 ์ฝ๊ธฐ โ†’ โœ“ ์บ์‹œ ํžˆํŠธ (1 ns)
3. I2 ์ฝ๊ธฐ โ†’ โœ“ ์บ์‹œ ํžˆํŠธ (1 ns)
...
17. I16 ์ฝ๊ธฐ โ†’ ์บ์‹œ ๋ฏธ์Šค โ†’ ๋‹ค์Œ 64 ๋ฐ”์ดํŠธ ๊ฐ€์ ธ์˜ด

ํ‰๊ท  ๋น„์šฉ: 100 ns / 16 ์š”์†Œ = 6 ns per ์š”์†Œ.


4. LinkedList ์˜ ์บ์‹œ ๋ฏธ์Šค ์ง€์˜ฅ

์ฒ˜๋ฆฌ:
1. Node 0 ์ฝ๊ธฐ โ†’ ์บ์‹œ ๋ฏธ์Šค โ†’ 100 ns
2. Node 0.next ๋”ฐ๋ผ Node 1 ์ฝ๊ธฐ โ†’ ๋˜ ์บ์‹œ ๋ฏธ์Šค โ†’ 100 ns
3. Node 1.next ๋”ฐ๋ผ Node 2 ์ฝ๊ธฐ โ†’ ๋˜ ์บ์‹œ ๋ฏธ์Šค โ†’ 100 ns
...

ํ‰๊ท  ๋น„์šฉ: 100 ns per ์š”์†Œ (ArrayList ์˜ 16๋ฐฐ).


5. ์‹ค์ธก ๊ฒฐ๊ณผ โ€” 100๋งŒ ๊ฐœ ์ˆœํšŒ

int N = 1_000_000;

// ArrayList
for (Integer i : arrayList) sum += i;  // ์•ฝ 5 ms

// LinkedList
for (Integer i : linkedList) sum += i;  // ์•ฝ 50 ms

โ†’ 10๋ฐฐ ์ฐจ์ด.


6. ์ถ”๊ฐ€ ๋น„์šฉ โ€” Node ๊ฐ์ฒด ์˜ค๋ฒ„ํ—ค๋“œ

LinkedList ์˜ ๊ฐ Node:

private static class Node<E> {
    E item;       // 4~8 ๋ฐ”์ดํŠธ
    Node<E> next; // 4~8 ๋ฐ”์ดํŠธ
    Node<E> prev; // 4~8 ๋ฐ”์ดํŠธ
}
// + ๊ฐ์ฒด ํ—ค๋” 16 ๋ฐ”์ดํŠธ
// = ์•ฝ 32~40 ๋ฐ”์ดํŠธ per ์š”์†Œ

ArrayList:

Object[] elementData;  // 4~8 ๋ฐ”์ดํŠธ per ์ฐธ์กฐ

๋ฉ”๋ชจ๋ฆฌ ์ฐจ์ด:

  • ArrayList: 8 ๋ฐ”์ดํŠธ / ์š”์†Œ
  • LinkedList: 40 ๋ฐ”์ดํŠธ / ์š”์†Œ (5๋ฐฐ)

100๋งŒ ์š”์†Œ:

  • ArrayList: ~8 MB
  • LinkedList: ~40 MB

โ†’ GC ๋ถ€๋‹ด ์ฆ๊ฐ€.


7. ์ข…ํ•ฉ ๋น„๊ต

์ธก๋ฉดArrayListLinkedList
๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ์น˜์—ฐ์†ํฉ์–ด์ง
์บ์‹œ ํ™œ์šฉ๋งค์šฐ ๋†’์Œ๊ฑฐ์˜ ์—†์Œ
L1 ํžˆํŠธ์œจ~95%~5%
ํ‰๊ท  ์ ‘๊ทผ ์‹œ๊ฐ„~6 ns~100 ns
๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ1๋ฐฐ5๋ฐฐ
GC ๋ถ€๋‹ด์ ์Œํผ

8. ๊ฒฐ๋ก 

"์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„ (Big-O) ๋Š” ์‹œ์ž‘์ ์ด์ง€ ๊ฒฐ์ •์ ์ด ์•„๋‹ˆ๋‹ค.
ํ˜„๋Œ€ CPU ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ํŒจํ„ด์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„๋ฅผ ์••๋„ ํ•œ๋‹ค.
ArrayList ์˜ ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ = CPU ์บ์‹œ ์นœํ™” = ๊ฑฐ์˜ ๋ชจ๋“  ์‹ค๋ฌด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋น ๋ฆ„.
LinkedList ์˜ ํฉ์–ด์ง„ Node = ์บ์‹œ ๋ฏธ์Šค ์ง€์˜ฅ = ๊ฑฐ์˜ ๋ชจ๋“  ์‹ค๋ฌด์—์„œ ๋А๋ฆผ.
์‹œ๋‹ˆ์–ด์˜ ๊นจ๋‹ฌ์Œ โ€” ์ด๋ก ๊ณผ ์‹ค๋ฌด์˜ ๊ดด๋ฆฌ๋ฅผ ์ธ์‹ํ•˜๊ณ  ์ธก์ •์œผ๋กœ ๊ฒ€์ฆ."


Q2: 100๋งŒ ๊ฐœ ๋ฐ์ดํ„ฐ์˜ ์ค‘๊ฐ„์— 1๋งŒ ๋ฒˆ ์‚ฝ์ž…ํ•œ๋‹ค๋ฉด ์–ด๋А ๊ฒŒ ์ข‹์„๊นŒ?

ํ•œ ์ค„ ๋‹ต: ๋‘˜ ๋‹ค ๋น„์Šทํ•˜๊ฒŒ ๋А๋ฆผ (O(nยฒ)), ๊ทธ๋Ÿฌ๋‚˜ ArrayList ๊ฐ€ ์•ฝ๊ฐ„ ๋” ๋น ๋ฆ„. ์ด๋Ÿฐ ์‹œ๋‚˜๋ฆฌ์˜ค๋ผ๋ฉด ์ž๋ฃŒ๊ตฌ์กฐ ์ž์ฒด๋ฅผ ์žฌ๊ณ  ํ•ด์•ผ ํ•จ.

์ƒ์„ธ ์„ค๋ช…:

1. ํ‘œ๋ฉด์  ๋ถ„์„

ArrayList ์ค‘๊ฐ„ ์‚ฝ์ž…:

  • ์œ„์น˜ ์ฐพ๊ธฐ: O(1) (์ธ๋ฑ์Šค ์ง์ ‘)
  • ๋’ค ์š”์†Œ ์ด๋™: O(n)
  • ํ•ฉ๊ณ„: O(n) per ์‚ฝ์ž…

LinkedList ์ค‘๊ฐ„ ์‚ฝ์ž…:

  • ์œ„์น˜ ์ฐพ๊ธฐ: O(n) โ€” ์ฒ˜์Œ๋ถ€ํ„ฐ ํƒ์ƒ‰!
  • ๋…ธ๋“œ ์—ฐ๊ฒฐ: O(1)
  • ํ•ฉ๊ณ„: O(n) per ์‚ฝ์ž…

โ†’ ๋‘˜ ๋‹ค O(n) โ€” Big-O ๋Š” ๊ฐ™์Œ.


2. 1๋งŒ ๋ฒˆ ๋ฐ˜๋ณต ์‹œ

100๋งŒ + 1๋งŒ ๋ฒˆ ์‚ฝ์ž… = ์•ฝ 100์–ต ๋ฒˆ์˜ ์ž‘์—… = O(nยฒ).

List<Integer> list = ...;  // 100๋งŒ ๊ฐœ
for (int i = 0; i < 10000; i++) {
    list.add(500000, value);  // ์ค‘๊ฐ„์— ์‚ฝ์ž…
}

์‹œ๊ฐ„:

  • ArrayList: ์•ฝ ์ˆ˜ ๋ถ„~์ˆ˜์‹ญ ๋ถ„
  • LinkedList: ์•ฝ ์ˆ˜ ๋ถ„~์ˆ˜์‹ญ ๋ถ„ (๋น„์Šท)

3. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์ˆ˜ ํ•ญ์ด ๋‹ค๋ฆ„

ArrayList ์˜ ์ค‘๊ฐ„ ์‚ฝ์ž…:

  • System.arraycopy ์‚ฌ์šฉ โ†’ ๋งค์šฐ ๋น ๋ฅธ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ
  • CPU SIMD ํ™œ์šฉ ๊ฐ€๋Šฅ
  • 50๋งŒ ์š”์†Œ ์ด๋™: ~2 ms

LinkedList ์˜ ์ค‘๊ฐ„ ์‚ฝ์ž…:

  • 50๋งŒ ๋ฒˆ์˜ node = node.next ํƒ์ƒ‰
  • ๊ฐ ํƒ์ƒ‰๋งˆ๋‹ค ์บ์‹œ ๋ฏธ์Šค
  • 50๋งŒ ๋…ธ๋“œ ํƒ์ƒ‰: ~50 ms

โ†’ ArrayList ๊ฐ€ ์•ฝ 25๋ฐฐ ๋น ๋ฆ„ (์ƒ์ˆ˜ ํ•ญ ์ฐจ์ด).


4. ์‹ค์ธก (๋Œ€๋žต)

int N = 1_000_000;
int M = 10_000;

// ArrayList
List<Integer> arr = new ArrayList<>(/* N items */);
for (int i = 0; i < M; i++) {
    arr.add(N / 2, i);
}
// ์•ฝ 30~60์ดˆ

// LinkedList
List<Integer> lnk = new LinkedList<>(/* N items */);
for (int i = 0; i < M; i++) {
    lnk.add(N / 2, i);
}
// ์•ฝ ๋ถ„ ๋‹จ์œ„ (์‚ฌ์‹ค์ƒ ์‚ฌ์šฉ ๋ถˆ๊ฐ€)

5. ๋” ๋‚˜์€ ๋Œ€์•ˆ โ€” ์ž๋ฃŒ๊ตฌ์กฐ ์žฌ๊ณ 

์ด๋Ÿฐ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” List ์ž์ฒด๊ฐ€ ๋ถ€์ ํ•ฉ.

๋Œ€์•ˆ 1: TreeMap (์ •๋ ฌ ํ‚ค)

TreeMap<Integer, Integer> map = new TreeMap<>();
map.put(50, value);  // O(log n)

๋Œ€์•ˆ 2: ์ผ๊ด„ ์ฒ˜๋ฆฌ (Batch)

// 1๋งŒ ๊ฐœ๋ฅผ ๋ชจ์•„์„œ ํ•œ ๋ฒˆ์— ์ •๋ ฌ/๋ณ‘ํ•ฉ
List<Integer> batch = collect();
list.addAll(batch);
Collections.sort(list);  // O(n log n)

๋Œ€์•ˆ 3: ๋‹ค๋ฅธ ์ž๋ฃŒ๊ตฌ์กฐ (Skip List, B-Tree)

// ์ž๋ฐ” ํ‘œ์ค€์€ ์—†์Œ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•„์š”

๋Œ€์•ˆ 4: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

-- DB ์˜ ์ธ๋ฑ์Šค ํ™œ์šฉ โ€” 100๋งŒ ํ–‰์—์„œ๋„ O(log n)
INSERT INTO table VALUES (...);

6. ๋ฉด์ ‘ ๋‹ต๋ณ€ ํŒจํ„ด

"100๋งŒ ๋ฐ์ดํ„ฐ์— 1๋งŒ ๋ฒˆ ์ค‘๊ฐ„ ์‚ฝ์ž…" ์งˆ๋ฌธ์ด ๋‚˜์˜จ๋‹ค๋ฉด:

  1. ํ‘œ๋ฉด์  ๋‹ต (1์ ): "LinkedList ๊ฐ€ ์‚ฝ์ž…์€ O(1) ์ด๋ผ ๋” ๋น ๋ฆ„"

  2. ์ค‘๊ธ‰ ๋‹ต (3์ ): "๋‘˜ ๋‹ค O(n) โ€” LinkedList ๋Š” ์œ„์น˜ ํƒ์ƒ‰ O(n) ์ด ์ถ”๊ฐ€๋จ"

  3. ์‹œ๋‹ˆ์–ด ๋‹ต (5์ ):

    • "๋‘˜ ๋‹ค O(nยฒ) ๋กœ ๋ถ€์ ํ•ฉ"
    • "ArrayList ๊ฐ€ ์ƒ์ˆ˜ ํ•ญ์ด ์ž‘์•„ ์•ฝ๊ฐ„ ๋น ๋ฆ„ (System.arraycopy + ์บ์‹œ)"
    • "์ง„์งœ ๋‹ต์€ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์žฌ๊ณ ํ•˜๋Š” ๊ฒƒ โ€” TreeMap, ์ผ๊ด„ ์ฒ˜๋ฆฌ, DB ๋“ฑ"
    • "๋ฆฌ์–ผ์›”๋“œ์—์„œ ์ด๋Ÿฐ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ๋‚˜์˜ค๋ฉด ์š”๊ตฌ์‚ฌํ•ญ ์ž์ฒด๋ฅผ ๋ถ„์„ํ•ด์•ผ ํ•จ"

7. ๊ฒฐ๋ก 

"100๋งŒ + 1๋งŒ ์ค‘๊ฐ„ ์‚ฝ์ž…์€ ์ž๋ฃŒ๊ตฌ์กฐ ์„ ํƒ ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ ์„ค๊ณ„ ๋ฌธ์ œ.
ArrayList ์™€ LinkedList ๋ชจ๋‘ O(nยฒ) ๋กœ ๋ถ€์ ํ•ฉ.
์ง„์งœ ์‹œ๋‹ˆ์–ด๋Š” '๋‘˜ ์ค‘ ์–ด๋А ๊ฒƒ?' ์ด ์•„๋‹Œ '์™œ ์ด๋Ÿฐ ํŒจํ„ด์ด ํ•„์š”ํ•œ๊ฐ€?' ๋ฅผ ๋ฌป๋Š”๋‹ค.
์ž์ฃผ ๋ฐ”๋€Œ๋Š” ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ = TreeMap, ์ธ๋ฑ์Šค = DB, ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ = ์ •๋ ฌ ํ›„ ๊ฒ€์ƒ‰."


๋‹ค์Œ Unit์œผ๋กœ

  • HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ โ˜…โ˜…โ˜… ํ•™์Šต ์ค€๋น„ ์™„๋ฃŒ (Phase 6 ์˜ ์ •์ )
  • hashCode ์™€ equals ์˜ ๊ด€๊ณ„๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค
  • ํ•ด์‹œ ์ถฉ๋Œ๊ณผ ํŠธ๋ฆฌํ™” (Java 8+) ๋ฅผ ๋งŒ๋‚  ์ค€๋น„ ์™„๋ฃŒ
profile
Software Developer

0๊ฐœ์˜ ๋Œ“๊ธ€