Skip to content

Latest commit

ย 

History

History
675 lines (515 loc) ยท 24.6 KB

Collection.md

File metadata and controls

675 lines (515 loc) ยท 24.6 KB

Collection

Collection
List Interface
Set Interface
Map Interface


Collection

Untitled

Java์˜ Collection๋ž€ ๋ฐ์ดํ„ฐ์˜ ์ง‘ํ•ฉ, ๊ทธ๋ฃน์„ ์˜๋ฏธํ•œ๋‹ค.

  • Java Collections Framework(JCF)๋Š” Collection๊ณผ ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋Š” interface๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • Collection Interface๋Š” ํฌ๊ฒŒ List, Set, Queue 3๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜๋œ๋‹ค.
  • Map ์ธํ„ฐํŽ˜์ด์Šค๋Š” Collection ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์†๋ฐ›์ง€ ์•Š์ง€๋งŒ Collection์œผ๋กœ ๋ถ„๋ฅ˜ํ•œ๋‹ค.

Collection ํŠน์ง•

์ปฌ๋ ‰์…˜ ํŠน์ง•
ArrayList ๋ฐฐ์—ด๊ธฐ๋ฐ˜, ๋ฐ์ดํ„ฐ์˜ ์ถ”๊ฐ€์™€ ์‚ญ์ œ์— ๋ถˆ๋ฆฌ, ์ˆœ์ฐจ์ ์ธ ์ถ”๊ฐ€/์‚ญ์ œ๋Š” ์ œ์ผ ๋น ๋ฆ„, ์ž„์˜์˜ ์š”์†Œ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ฑ์ด ๋›ฐ์–ด๋‚จ
Linked List ์—ฐ๊ฒฐ๊ธฐ๋ฐ˜, ๋ฐ์ดํ„ฐ์˜ ์ถ”๊ฐ€์™€ ์‚ญ์ œ์— ์œ ๋ฆฌ, ์ž„์˜์˜ ์š”์†Œ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ฑ์ด ์ข‹์ง€ ์•Š๋‹ค.
HashMap ๋ฐฐ์—ด๊ณผ ์—ฐ๊ฒฐ์ด ๊ฒฐํ•ฉ๋œ ํ˜•ํƒœ, ์ถ”๊ฐ€/์‚ญ์ œ/๊ฒ€์ƒ‰/์ ‘๊ทผ์„ฑ์ด ๋ชจ๋‘ ๋›ฐ์–ด๋‚จ, ๊ฒ€์ƒ‰์—๋Š” ์ตœ๊ณ  ์„ฑ๋Šฅ์„ ๋ณด์ธ๋‹ค.
TreeMap ์—ฐ๊ฒฐ๊ธฐ๋ฐ˜, ์ •๋ ฌ๊ณผ ๊ฒ€์ƒ‰(ํŠนํžˆ ๋ฒ”์œ„๊ฒ€์ƒ‰)์— ์ ํ•ฉ, ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ์€ HashMap ๋ณด๋‹ค ๋–จ์–ด์ง„๋‹ค.
HashSet ๋‚ด๋ถ€์ ์œผ๋กœ HashMap์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„
TreeSet ๋‚ด๋ถ€์ ์œผ๋กœ TreeMap์„ ์ด์šฉํ•ด์„œ ๊ตฌํ˜„
LinkedHashMap HashMap์— ์ €์žฅ์ˆœ์„œ ์œ ์ง€๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€
LinkedHashSet HashSet์— ์ €์žฅ์ˆœ์„œ ์œ ์ง€๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€

Collections ํด๋ž˜์Šค

Collections ํด๋ž˜์Šค๋Š” ๋ชจ๋“  ์ปฌ๋ ‰์…˜์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋‹ด๋‹นํ•œ๋‹ค.

  • ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋กœ์จ static ๋ฉ”์†Œ๋“œ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ณ  ์ปฌ๋ ‰์…˜๋“ค์„ ์ปจํŠธ๋กคํ•˜๋Š”๋ฐ์— ์‚ฌ์šฉ๋œ๋‹ค.
  • ์ฃผ์˜ํ•  ์ ์€ ์ž๋ฐ”์˜ Collection์€ ์ธํ„ฐํŽ˜์ด์Šค์ด๋ฉฐ, Collections๋Š” ํด๋ž˜์Šค๋ผ๋Š” ์ ์ด๋‹ค.

๋Œ€ํ‘œ์ ์ธ ๋ฉ”์†Œ๋“œ

  • ์ •๋ ฌ(Sorting) : ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์š”์†Œ๊ฐ€ ์˜ค๋ฆ„์ฐจ์ˆœ์ด ๋˜๋„๋ก ๋ฆฌ์ŠคํŠธ๋ฅผ ์žฌ์ •๋ ฌํ•จ
  • ์…”ํ”Œ๋ง(Shuffling) : ์…”ํ”Œ๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋žœ๋ค์œผ๋กœ ๋ชฉ๋ก์„ ์žฌ์ •๋ ฌํ•จ (์šฐ์—ฐํ•œ ๊ฒŒ์ž„์„ ๊ตฌํ˜„ํ•  ๋•Œ ์œ ์šฉ)
  • ํƒ์ƒ‰ (Searching) : ์ด์ง„ ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ •๋ ฌ๋œ ๋ชฉ๋ก์—์„œ ์ง€์ •๋œ ์š”์†Œ๋ฅผ ๊ฒ€์ƒ‰

List Interface

List๋ž€ ์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ์ง‘ํ•ฉ์ด๋‹ค.

  • List Interface์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค์—๋Š” Vector, ArrayList, LinkedList๊ฐ€ ์žˆ๋‹ค.
  • List์˜ index์—๋Š” ๋ฐ์ดํ„ฐ์˜ ์ฃผ์†Œ๊ฐ’(์ฐธ์กฐ๊ฐ’)์ด ๋“ค์–ด์žˆ๋‹ค.
    • ๋ฐ์ดํ„ฐ ์ž์ฒด๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ์ฃผ์†Œ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค
    • null ์ด ์ €์žฅ๋  ๊ฒฝ์šฐ ํ•ด๋‹น index์—๋Š” ์ฐธ์กฐ๊ฐ’ ์กฐ์ฐจ ๋“ค์–ด์žˆ์ง€ ์•Š๋‹ค.
  • ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ ํ—ˆ์šฉํ•œ๋‹ค
    • List ์† ์ค‘๋ณต๋œ ๋ฐ์ดํ„ฐ๋Š” ๋ชจ๋‘ ๋™์ผํ•œ ์ฃผ์†Œ๊ฐ’์„ ์ฐธ์กฐํ•œ๋‹ค

๐Ÿ“ŒArrayList

List<String> list = new ArrayList<>(Arrays.asList(1, 2, 3));

Untitled

ArrayList๋ž€ ํฌ๊ธฐ๊ฐ€ ๊ฐ€๋ณ€์ ์œผ๋กœ ๋ณ€ํ•˜๋Š” ์„ ํ˜• ๋ฆฌ์ŠคํŠธ์ด๋‹ค.

  • Object ๋ฐฐ์—ด ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  index๋กœ Object ๋ฐฐ์—ด ์† ๊ฐ์ฒด๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
  • Capacity(์ €์žฅ ์šฉ๋Ÿ‰) ์„ ์ดˆ๊ณผํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ €์žฅ ์šฉ๋Ÿ‰์„ ๋Š˜๋ฆฐ๋‹ค. (๋” ํฐ ํฌ๊ธฐ์˜ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜์—ฌ ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์— ๋ณต์‚ฌ)

ArrayList๋Š” ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ €์žฅ ์šฉ๋Ÿ‰์„ ๋Š˜๋ฆด๊นŒ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด, ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ์ƒˆ๋กœ์šด Object ๋ฐฐ์—ด์„ ๊ธฐ์กด Object ๋ฐฐ์—ด์˜ 1.5๋ฐฐ ํฌ๊ธฐ๋กœ ํ™•์žฅ์‹œํ‚จ๋‹ค

์ด์œ  ์„ค๋ช…
/**
    * Default initial capacity.
    */
private static final int DEFAULT_CAPACITY = 10;

/**
    * Shared empty array instance used for empty instances.
    */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
    * Shared empty array instance used for default sized empty instances. We
    * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
    * first element is added.
    */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
    * The array buffer into which the elements of the ArrayList are stored.
    * The capacity of the ArrayList is the length of this array buffer. Any
    * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    * will be expanded to DEFAULT_CAPACITY when the first element is added.
    */
transient Object[] elementData; // non-private to simplify nested class access

ArrayList๋Š” ๋‚ด๋ถ€์—์„œ Object ๋ฐฐ์—ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค

  • ArrayList์˜ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด elementData ๋ฐฐ์—ด์˜ capacity๋ฅผ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋กœ ArrayList๋ฅผ ์ƒ์„ฑํ•˜๋ฉด elementData์— EMPTY_ELEMENTDATA ๋ผ๋Š” ๋นˆ Object ๋ฐฐ์—ด์ด ํ• ๋‹น๋œ๋‹ค
  • ์ฐธ๊ณ ) transient๋ž€ ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ œ์™ธํ•˜๊ณ  ์‹ถ์€ ๋ณ€์ˆ˜์— ์„ ์–ธํ•˜๋Š” ํ‚ค์›Œ๋“œ์ด๋‹ค.
/**
    * 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;
}

/**
    * Appends the specified element to the end of this list.
    *
    * @param e element to be appended to this list
    * @return {@code true} (as specified by {@link Collection#add})
    */
public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
}

if (s == elementData.length)

  • ArrayList์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด s (ํ˜„์žฌ๊นŒ์ง€ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜)์™€ elementData.length (Object ๋ฐฐ์—ด์˜ ํ• ๋‹น๋œ ๊ธธ์ด)๋ฅผ ๋น„๊ตํ•˜์—ฌ Object ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ์กฐ์ •ํ•ด์•ผ ํ• ์ง€ ํŒ๋‹จํ•œ๋‹ค.
    • elementData = grow(); ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด Object ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ๋Š˜์–ด๋‚˜๊ฒŒ ํ•ด์ค€๋‹ค.
/**
    * 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) {
    return elementData = Arrays.copyOf(elementData,
                                        newCapacity(minCapacity));
}

private Object[] grow() {
    return grow(size + 1);
}
  • grow(int minCapacity) ๋ฉ”์†Œ๋“œ๋Š” ๊ธฐ์กด์˜ elementData ๋ฐฐ์—ด์— newCapacity(minCapacity)) ๊ธธ์ด ๋งŒํผ์˜ ์ƒˆ๋กœ์šด Object ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. (minCapacity๋Š” ํ˜„์žฌ ArrayList ์‚ฌ์ด์ฆˆ + 1์ด๋‹ค)
/**
    * The maximum size of array to allocate (unless necessary).
    * Some VMs reserve some header words in an array.
    * Attempts to allocate larger arrays may result in
    * OutOfMemoryError: Requested array size exceeds VM limit
    */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // ๐Ÿ‘‰ 2147483639

/**
    * Returns a capacity at least as large as the given minimum capacity.
    * Returns the current capacity increased by 50% if that suffices.
    * Will not return a capacity greater than MAX_ARRAY_SIZE unless
    * the given minimum capacity is greater than MAX_ARRAY_SIZE.
    *
    * @param minCapacity the desired minimum capacity
    * @throws OutOfMemoryError if minCapacity is less than zero
    */
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // ๐Ÿ‘‰ ๊ธฐ์กด ์šฉ๋Ÿ‰์˜ 1.5๋ฐฐ
    if (newCapacity - minCapacity <= 0) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);
}
  • newCapacity(minCapacity) ๋ฉ”์†Œ๋“œ๋Š” ์ƒˆ๋กญ๊ฒŒ ํ• ๋‹นํ•  ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.
    • ํ• ๋‹น๋œ Object ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ x 1.5 (newCapacity)๊ฐ€ ํ˜„์žฌ ์‚ฌ์ด์ฆˆ + 1 (minCapacity) ๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์„ ๋•Œ, elementData๊ฐ€ ๋นˆ Object ๋ฐฐ์—ด์ด๋ผ๋ฉด DEFAULT_CAPACITY (10) ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ํ• ๋‹น๋œ Object ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ x 1.5 (newCapacity)๊ฐ€ ํ˜„์žฌ ์‚ฌ์ด์ฆˆ + 1 (minCapacity) ๋ณด๋‹ค ํฌ๋ฉด, ํ• ๋‹น๋œ Object ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ x 1.5 (newCapacity) ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (์ตœ๋Œ€ ํฌ๊ธฐ MAX_ARRAY_SIZE๋Š” Integer.MAX_VALUE - 8 ==2147483639 ์ด๋‹ค)
  • ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ์ƒˆ๋กœ์šด Object ๋ฐฐ์—ด์„ ๊ธฐ์กด Object ๋ฐฐ์—ด์˜ 1.5๋ฐฐ ํฌ๊ธฐ๋กœ ํ™•์žฅ์‹œํ‚จ๋‹ค
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE)
        ? Integer.MAX_VALUE
        : MAX_ARRAY_SIZE;
}
  • ๋งŒ์•ฝ newCapacity(minCapacity) ๋ฉ”์†Œ๋“œ์—์„œ ํ• ๋‹น๋œ Object ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ x 1.5 (newCapacity)๊ฐ€ MAX_ARRAY_SIZE๋ฅผ ๋„˜์–ด๊ฐˆ ๊ฒฝ์šฐ hugeCapacity(minCapacity) ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค
    • ํ˜„์žฌ ์‚ฌ์ด์ฆˆ + 1 (minCapacity)๊ฐ€ MAX_ARRAY_SIZE๋ณด๋‹ค ํฌ๋‹ค๋ฉด, ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์˜ ์‚ฌ์ด์ฆˆ๋ฅผ Integer.MAX_VALUE (2147483647)๋กœ ์„ค์ •ํ•œ๋‹ค.
    • ํ˜„์žฌ ์‚ฌ์ด์ฆˆ + 1 (minCapacity)๊ฐ€ int์˜ ํ‘œํ˜„ ๋ฒ”์œ„๋ฅผ ๋„˜์–ด์„œ๋ฉด OutOfMemoryError๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

๋ฐฐ์—ด๊ณผ ArrayList์˜ ์ฐจ์ด์ 

  • ๋ฐฐ์—ด์€ ์ƒ์„ฑํ•  ๋•Œ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ๊ณ  ์‚ฌ์šฉ์ค‘์— ํฌ๊ธฐ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค.
  • ArrayList๋Š” ์ €์žฅ ์šฉ๋Ÿ‰์ด ์ดˆ๊ณผํ•˜๋ฉด ์ž๋™์œผ๋กœ ์šฉ๋Ÿ‰์„ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๋‹ค.

ArrayList์˜ ์‹œ๊ฐ„๋ณต์žก๋„ (์ฐธ๊ณ )

  • ์กฐํšŒ
    • index๋ฅผ ํ†ตํ•ด O(1)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์‚ฝ์ž…/์‚ญ์ œ
    • ๋‚ด๋ถ€์ ์œผ๋กœ Object ๋ฐฐ์—ด๋กœ ๊ตฌ์„ฑ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ์ค‘๊ฐ„ ๋˜๋Š” ๋งจ ์•ž์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…, ์‚ญ์ œํ•  ๋•Œ ์ตœ์•…์˜ ๊ฒฝ์šฐ O(N)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค
    • ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ์˜ ์œ„์น˜๊ฐ€ ๋งจ ๋’ค์ด๊ณ , Object ๋ฐฐ์—ด์— ๊ฐ€์šฉ ๊ณต๊ฐ„์ด ์žˆ๋‹ค๋ฉด O(1)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค

๐Ÿ“ŒVector

List<E> list = new Vector<>();

Vector ๋Š” ArrayList์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค์ด๋‹ค.

  • ๋‚ด๋ถ€์—์„œ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ArrayList๋ณด๋‹ค ์ƒ๋Œ€์ ์œผ๋กœ ์„ฑ๋Šฅ์ด ์ข‹์ง€ ์•Š๋‹ค
  • ๊ธฐ์กด ์ฝ”๋“œ์™€ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ๋‚จ์•„์žˆ๋‹ค

ArrayList์™€ Vector์˜ ์ฐจ์ด์ 

  • ArrayList๋Š” ์ž๋™์œผ๋กœ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Thread Safe ํ•˜์ง€ ์•Š๋‹ค.
  • Vector๋Š” Thread์˜ ์ˆ˜์™€ ์ƒ๊ด€์—†์ด ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Thread Safe ํ•˜์ง€๋งŒ ์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์กฐ์ฐจ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฏ€๋กœ ArrayList์— ๋น„ํ•ด ์„ฑ๋Šฅ์ด ์ข‹์ง€ ์•Š๋‹ค

๐Ÿ“ŒLinkedList

List<E> list = new LinkedList<>();

// LinkedList์˜ linkFirst ๋ฉ”์†Œ๋“œ
/**
 * Links e as first element.
 */
private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

// LinkedList.class์˜ private class์ธ Node
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;
        }
    }

LinkedList ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ Node๋กœ ๊ฐ์‹ธ๊ณ , Node๋ฅผ ํ†ตํ•ด ์–‘๋ฐฉํ–ฅ ํฌ์ธํ„ฐ ๊ตฌ์กฐ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค

  • Stack, Queue, Deque๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
  • ๋ฐ์ดํ„ฐ ์‚ฝ์ž…, ์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํ•  ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ์˜ ํฌ์ธํ„ฐ ์ •๋ณด๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ์œ ์šฉํ•˜๋‹ค

LinkedList์˜ ์‹œ๊ฐ„๋ณต์žก๋„ (์ฐธ๊ณ )

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    /**
     * Pointer to first node.
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     */
    transient Node<E> last;
  • ์กฐํšŒ
    • first ํฌ์ธํ„ฐ๋ถ€ํ„ฐ ํƒ€๊ฒŸ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์•…์˜ ๊ฒฝ์šฐ O(N) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค
  • ์‚ฝ์ž…/์‚ญ์ œ
    • ๋‚˜๋จธ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ shiftํ•  ํ•„์š” ์—†์ด ์‚ฝ์ž…/์‚ญ์ œํ•  ๋ฐ์ดํ„ฐ(๋…ธ๋“œ)์˜ ํฌ์ธํ„ฐ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค. (O(1)) ํ•˜์ง€๋งŒ ์‚ฝ์ž…/์‚ญ์ œ ํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ์˜ ์œ„์น˜๊ฐ€ ์ค‘๊ฐ„์— ์žˆ๋‹ค๋ฉด ํƒ์ƒ‰ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์•…์˜ ๊ฒฝ์šฐ O(N) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค.

ArrayList์™€ LinkedList์˜ ์ฐจ์ด์  (์ฐธ๊ณ )

ArrayList LinkedList
์กฐํšŒ/์ˆ˜์ • O(1) index๋กœ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค. O(N) ์ˆœ์„œ๋Š” ์žˆ์ง€๋งŒ, index๊ฐ€ ์—†์–ด iterator๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํƒ์ƒ‰ํ•ด์•ผํ•œ๋‹ค.
add (์‹œ์ž‘) O(N) O(1)
add (์ค‘๊ฐ„) O(N) O(N)
add (๋) O(1) O(1)
remove (์‹œ์ž‘) O(N) ํ•ด๋‹น index์˜ +1 ์œ„์น˜๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋ชจ๋‘ 1์นธ์”ฉ ์•ž์œผ๋กœ ๋‹น๊ฒจ์•ผ ํ•œ๋‹ค. O(1) ์–‘๋ฐฉํ–ฅ ํฌ์ธํ„ฐ ์ •๋ณด๋งŒ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค.
remove (์ค‘๊ฐ„) O(N) O(N)
remove (๋) O(1) O(1)

๋ฐ์ดํ„ฐ์˜ ํƒ์ƒ‰์ด ๋นˆ๋ฒˆํ•˜๋‹ค๋ฉด ArrayList ์ด ๋ฐ”๋žŒ์งํ•˜๊ณ , ๋ฐ์ดํ„ฐ์˜ ์ถ”๊ฐ€, ์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํ•˜๋‹ค๋ฉด LinkedList ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค ([ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค] ํ‘œ ํŽธ์ง‘ ๋ฌธ์ œ)


๊ทธ๋ ‡๋‹ค๋ฉด ์ถ”๊ฐ€, ์‚ญ์ œ, ์กฐํšŒ๊ฐ€ ๋นˆ๋ฒˆํ•  ๊ฒฝ์šฐ ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผํ• ๊นŒ?

ArrayList LinkedList
add 6 ms 3 ms
get 0.01 ms 157 ms
remove 135 ms 126 ms

๊ตณ์ด ๊ณ ๋ฅด์ž๋ฉด ArrayList์ด๋‹ค. ์กฐํšŒ์˜ ๊ฒฝ์šฐ ArrayList๊ฐ€ LinkedList๋ณด๋‹ค ๋งค์šฐ ๋น ๋ฅด์ง€๋งŒ, ์‚ฝ์ž…/์‚ญ์ œ์˜ ๊ฒฝ์šฐ ArrayList์™€ LinkedList์˜ ์†๋„ ์ฐจ์ด๊ฐ€ ์ž‘๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


Set Interface

Set์ด๋ž€ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ์˜ ์ง‘ํ•ฉ์ด๋‹ค.

  • Set Interface์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋กœ HashSet , TreeSet ์ด ์žˆ๋‹ค.
  • Set์€ index ๊ฐœ๋…์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฅผ ํƒ์ƒ‰ํ•˜๋ ค๋ฉด iterator๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
    • Iterator<String> iter = set.iterator();

๐Ÿ“ŒHashSet

Set<E> set = new HashSet<>();

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
private transient HashMap<E,Object> map;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

// HashSet์˜ ์ƒ์„ฑ์ž
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
    map = new HashMap<>();
}

// HashSet์˜ add ๋ฉ”์†Œ๋“œ
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

HashSet์˜ ๋‚ด๋ถ€๋ฅผ ์‚ดํŽด๋ณด๋ฉด HashMap์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

  • HashMap์€ key-value ์Œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” Map Interface์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค์ด๋‹ค. HashSet์—์„œ๋Š” HashMap์˜ key๋งŒ ์‚ฌ์šฉํ•˜๊ณ  value์—๋Š” dummy ๊ฐ’ PRESENT ๋ฅผ ์ฑ„์šด๋‹ค.

    ์ฆ‰ Set<E> set = new HashSet<>(); ์œผ๋กœ HashSet ๊ฐ์ฒด๋ฅผ ์„ ์–ธํ•˜๋ฉด key๊ฐ’์œผ๋กœ E๊ฐ์ฒด๊ฐ€ ์ฑ„์›Œ์ ธ์žˆ๊ณ  value์—๋Š” dummy ๊ฐ์ฒด๊ฐ€ ์ฑ„์›Œ์ง„ HashMap์ด ์ƒ์„ฑ๋œ๋‹ค.


HashSet์˜ ํŠน์ง•

  • ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค
  • key๊ฐ’์œผ๋กœ ํƒ€๊ฒŸ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค โ†’ O(1)
  • ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ค‘๋ณต ์ €์žฅํ•  ์ˆ˜ ์—†๋‹ค.

HashSet์— ์ค‘๋ณต ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์—†๋Š” ์ด์œ 

์ผ๋‹จ HashSet์€ ๋‚ด๋ถ€์ ์œผ๋กœ HashMap์„ ์‚ฌ์šฉํ•œ๋‹ค. HashMap์˜ key๋Š” ๊ฐ์ฒด์˜ ํ•ด์‹œ๊ฐ’์ด๋‹ค. ์ž๋ฐ”์—์„œ ๊ฐ์ฒด์˜ ํ•ด์‹œ๊ฐ’์€ hashCode() ๋ฉ”์†Œ๋“œ๋กœ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ hashCode() ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜ ๊ฐ’์€ intํ˜• ์ •์ˆ˜์ด๋‹ค. ๋‹ค์‹œ ๋งํ•ด ๊ฐ์ฒด์˜ original hash๊ฐ’์ด ๋‹ค๋ฅผ์ง€๋ผ๋„ hashCode()์˜ ๋ฐ˜ํ™˜ ๊ฐ’์ด ๋™์ผํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ๊ฐ์ฒด์˜ hashCode() ๊ฐ’์ด ๊ฐ™์œผ๋ฉด equals() ๋ฉ”์†Œ๋“œ๋กœ ๋™๋“ฑ๋น„๊ต๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋™๋“ฑ ๊ฐ์ฒด์ธ์ง€ ํŒ๋ณ„ํ•œ๋‹ค. (๋™๋“ฑ ๋น„๊ต๋Š” ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐ’ ์ž์ฒด๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด๋‹ค)

Untitled

์ด์ฒ˜๋Ÿผ HashMap์€ key-value์Œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์ „์— ๊ฐ์ฒด์˜ key๊ฐ’(hashCode() ๋ฐ˜ํ™˜ ๊ฐ’)์„ ๋ณด๊ณ  ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ์™€ ๋น„๊ตํ•œ๋‹ค. ๋งŒ์•ฝ hashCode() ๋ฐ˜ํ™˜ ๊ฐ’์ด ๊ฐ™์€ ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด, equals() ๋ฉ”์†Œ๋“œ๋กœ ๋™๋“ฑ ๋น„๊ต๋ฅผ ํ•œ๋ฒˆ ๋” ์ˆ˜ํ–‰ํ•œ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋™์ผํ•˜๋‹ค๋ฉด HashMap์— ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ด์™€ ๊ฐ™์€ ์ด์œ ๋กœ HashSet์— ์ค‘๋ณต ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์—†๋‹ค.

๐Ÿ“ŒTreeSet

TreeSet<Integer> tSet = new TreeSet<>();

NavigableSet<Integer> asc = tSet.descendingSet();
for(Integer a : asc) {
			System.out.println(a);
}//๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ

NavigableSet<Integer> sub = tSet.subSet(20, true, 40, true);
for(Integer s : sub) {
			System.out.println(s);
}//๋ฒ”์œ„ ์ง€์ • ์ถœ๋ ฅ

TreeSet์€ ์ •๋ ฌ ๋ฐฉ๋ฒ•์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” Set์ด๋‹ค

  • ๊ธฐ๋ณธ ์ •๋ ฌ์€ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ์ด๋‹ค.
  • ๋‚ด๋ถ€์ ์œผ๋กœ Red-Black Tree๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. (์ฐธ๊ณ )

Map Interface

Map์€ key-value ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐ์ดํ„ฐ(Map.Entry)์˜ ์ง‘ํ•ฉ์ด๋‹ค.

  • Map Interface์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค์—๋Š” HashMap, HashTable, TreeMap ๋“ฑ์ด ์žˆ๋‹ค
  • Map์€ key์˜ ์ค‘๋ณต์€ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ , value์˜ ์ค‘๋ณต์€ ํ—ˆ์šฉํ•œ๋‹ค. (๊ธฐ์กด์— ์ €์žฅ๋œ key์— ์ƒˆ๋กœ์šด value2๋ฅผ ์ €์žฅํ•˜๋ฉด ๊ธฐ์กด์˜ value1์ด ์ƒˆ๋กœ์šด value2๋กœ ๋Œ€์ฒด๋œ๋‹ค)
  • ๋ฐ์ดํ„ฐ(Map.Entry)์˜ ์ˆœ์„œ๊ฐ€ ์œ ์ง€๋˜์ง€ ์•Š๋Š”๋‹ค

๐Ÿ“ŒHashMap

HashMap<K, V> map = new HashMap<>();

HashMap์˜ put ๋ฉ”์†Œ๋“œ

put ๋ฉ”์†Œ๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜๋ฉด Node<K,V>๋ฐฐ์—ด์˜ ๋ฐ์ดํ„ฐ์˜ hash ๊ฐ’ & (Node ๋ฐฐ์—ดํฌ๊ธฐ-1) ์œ„์น˜์— value๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค.

์„ค๋ช…
/**
    * Associates the specified value with the specified key in this map.
    * If the map previously contained a mapping for the key, the old
    * value is replaced.
    *
    * @param key key with which the specified value is to be associated
    * @param value value to be associated with the specified key
    * @return the previous value associated with {@code key}, or
    *         {@code null} if there was no mapping for {@code key}.
    *         (A {@code null} return can also indicate that the map
    *         previously associated {@code null} with {@code key}.)
    */
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
  • HashMap.put(key, value) ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด hash(key)๋ฉ”์†Œ๋“œ์™€ putVal ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
/**
    * Computes key.hashCode() and spreads (XORs) higher bits of hash
    * to lower.  Because the table uses power-of-two masking, sets of
    * hashes that vary only in bits above the current mask will
    * always collide. (Among known examples are sets of Float keys
    * holding consecutive whole numbers in small tables.)  So we
    * apply a transform that spreads the impact of higher bits
    * downward. There is a tradeoff between speed, utility, and
    * quality of bit-spreading. Because many common sets of hashes
    * are already reasonably distributed (so don't benefit from
    * spreading), and because we use trees to handle large sets of
    * collisions in bins, we just XOR some shifted bits in the
    * cheapest possible way to reduce systematic lossage, as well as
    * to incorporate impact of the highest bits that would otherwise
    * never be used in index calculations because of table bounds.
    */
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

static ๋ฉ”์†Œ๋“œ hash(Object key) ๋Š”

  • ์‚ฝ์ž…ํ•  ๊ฐ์ฒด key == null ์ด๋ฉด โ†’ 0์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ์‚ฝ์ž…ํ•  ๊ฐ์ฒด key โ‰  null ์ด๋ฉด โ†’ ๊ฐ์ฒด์˜ hashCode() ๊ฐ’ (ํ•ด์‹œ๊ฐ’) ๊ณผ ์ด๋ฅผ unsigned right shiftํ•œ ๊ฐ’ ์„ XOR ์—ฐ์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
// putVal ๋ฉ”์†Œ๋“œ
/**
    * Implements Map.put and related methods.
    *
    * @param hash hash for key
    * @param key the key
    * @param value the value to put
    * @param onlyIfAbsent if true, don't change existing value
    * @param evict if false, the table is in creation mode.
    * @return previous value, or null if none
    */
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                    boolean evict) {
        // local variable
        Node<K,V>[] tab;
        Node<K,V> p;
        int n, i;

        // logic
                if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null) // ๐Ÿ‘‰ index == (n - 1) & hash
            tab[i] = newNode(hash, key, value, null);
        else {
                ...
}

// resize ๋ฉ”์†Œ๋“œ
final Node<K,V>[] resize() {
        ...
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        ...
}

// Node ํด๋ž˜์Šค
static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
        ...
}

Untitled

  • putVal ๋ฉ”์†Œ๋“œ โ†’ resize ๋ฉ”์†Œ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ณด๋ฉด HashMap์€ ๋‚ด๋ถ€์ ์œผ๋กœ Node ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    • Node ๋ฐฐ์—ด์ด๋ž€ ๊ณง LinkedList ๋ฐฐ์—ด์ด๋‹ค. (Node ๋ฐฐ์—ด์† Node ๊ฐ์ฒด๋Š” LinkedList์˜ head์ด๋‹ค.)
  • HashMap์˜ put ๋ฉ”์†Œ๋“œ๋Š” ์‚ฝ์ž…ํ•˜๋ ค๋Š” ๊ฐ์ฒด์˜ hash๊ฐ’(hash(key) ๋ฉ”์†Œ๋“œ์˜ ๋ฐ˜ํ™˜ ๊ฐ’)์„ Node ๋ฐฐ์—ด(LinkedList ๋ฐฐ์—ด)์˜ index(i = (n - 1) & hash)๋กœ ํ™œ์šฉํ•˜์—ฌ ํ•ด๋‹น LinkedList์— addํ•œ๋‹ค.
    • LinkedList ๋ฐฐ์—ด[๊ฐ์ฒด์˜ hash๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” index]์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด head์— addํ•˜๊ณ , ์žˆ๋‹ค๋ฉด tail์— addํ•œ๋‹ค. โ†’ O(1)
    • ํ•˜๋‚˜์˜ LinkedList์˜ ๊ฐ์ฒด๊ฐ€ 8๊ฐœ๊ฐ€ ๋˜๋ฉด LinkedList โ†’ Red-Black Tree๋กœ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋ณ€ํ™˜ํ•œ๋‹ค.
    • ํ•˜๋‚˜์˜ LinkedList์˜ ๊ฐ์ฒด๊ฐ€ 6๊ฐœ๊ฐ€ ๋˜๋ฉด Red-Black Tree โ†’ LinkedList๋กœ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋ณ€ํ™˜ํ•œ๋‹ค.

HashMap์˜ remove ๋ฉ”์†Œ๋“œ

Node<K,V>๋ฐฐ์—ด์˜ ๋ฐ์ดํ„ฐ์˜ hash ๊ฐ’ & (Node ๋ฐฐ์—ดํฌ๊ธฐ-1) ์œ„์น˜์— ์‚ญ์ œํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

  • Node<K, V> ๋ฐฐ์—ด์„ ์ˆœํšŒ ํƒ์ƒ‰ํ•˜๋ฉด์„œ ์‚ญ์ œํ•  ๋ฐ์ดํ„ฐ์˜ key๊ฐ’๊ณผ ๋™์ผํ•œ Node๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์žˆ๋‹ค๋ฉด ํ•ด๋‹น Node๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์—†์œผ๋ฉด null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๐Ÿ“ŒTreeMap

TreeMap<K, V> mymap = new TreeMap<>();

mymap.firstKey(); // ๊ฐ€์žฅ ์ž‘์€ ํ‚ค
mymap.lastKey(); // ๊ฐ€์žฅ ํฐ ํ‚ค
mymap.remove(1); // key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ œ๊ฑฐ

TreeMap์€ key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•œ๋‹ค.

  • TreeMap์€ TreeSet๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Red-Black Tree๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค

TreeMap์˜ ์ •๋ ฌ

  • K(key)๊ฐ€ ์ˆซ์ž ํƒ€์ž…์ด๋ฉด key ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ ฌํ•œ๋‹ค
  • K(key)๊ฐ€ ๋ฌธ์žํƒ€์ž…์ด๋ฉด key์˜ ์œ ๋‹ˆ์ฝ”๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ ฌํ•œ๋‹ค

์ •๋ ฌ ์ˆœ์„œ๋Š” leftChild ๋…ธ๋“œ < parent ๋…ธ๋“œ < rightChild ๋…ธ๋“œ ์ˆœ์„œ์ด๋‹ค. (Red-Black Tree๊ฐ€ BST์˜ ์ผ์ข…์ด๊ธฐ ๋•Œ๋ฌธ)


HashMap๊ณผ TreeMap์˜ ์ฐจ์ด

HashMap TreeMap
๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค key-value์Œ์˜ ๋ฐ์ดํ„ฐ์˜ key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ์„ ์œ ์ง€ํ•œ๋‹ค
key๊ฐ’์œผ๋กœ null์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. (์˜ค์ง ํ•˜๋‚˜๋งŒ) key๊ฐ’์œผ๋กœ null์„ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค.(key๋กœ ์ •๋ ฌ์„ ํ•˜๊ธฐ ๋•จ๋ฌธ)
TreeMap๋ณด๋‹ค ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค HashMap๋ณด๋‹ค ์†๋„๊ฐ€ ๋Š๋ฆฌ๋‹ค. (๋…ธ๋“œ ์‚ฝ์ž…/์‚ญ์ œ์‹œ Tree ๊ตฌ์กฐ๋ฅผ restructuring ํ•˜๊ธฐ ๋•Œ๋ฌธ)

TreeSet๊ณผ TreeMap์˜ ๊ณตํ†ต์ 

  • ๋ฐ์ดํ„ฐ์— ์ •๋ ฌ ์ˆœ์„œ๊ฐ€ ์žˆ๋‹ค.(์ •๋ ฌ ๊ธฐ์ค€์€ ๋ฐ์ดํ„ฐ์˜ key๊ฐ’(ํ•ด์‹œ๊ฐ’)์ด๋‹ค)
  • Red-Black Tree๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.
  • ํ•˜๋‚˜์˜ Node๋Š” value, left ๋…ธ๋“œ ์ฐธ์กฐ ๋ณ€์ˆ˜, right ๋…ธ๋“œ ์ฐธ์กฐ ๋ณ€์ˆ˜ 3๊ฐ€์ง€ ์ •๋ณด๋ฅผ ๊ฐ€์ง„๋‹ค

TreeSet๊ณผ TreeMap์˜ ์ฐจ์ด์ 

TreeSet TreeMap
์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ํ•œ ๊ฐœ๋ฟ์ด๋‹ค. (ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋Š” HashMap์˜ key๋กœ ์ €์žฅ๋œ๋‹ค) ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” key-value ๊ตฌ์กฐ์˜ Map.Entry์ด๋‹ค.

๋ฉด์ ‘ ์˜ˆ์ƒ ์งˆ๋ฌธ

List, Set, Map ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”

HashMap์˜ ๋™์ž‘ ์›๋ฆฌ๋ฅผ ์•„์‹œ๋‚˜์š”?

Java์˜ HashMap์—์„œ ํ•ด์‹œ ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๋Š” ๊ณผ์ •์„ ์„ค๋ช…ํ•ด์ฃผ์„ธ์š”

ArrayList์˜ ์‚ฌ์ด์ฆˆ๋Š” ์–ธ์ œ ๋Š˜๋ฆฌ๋‚˜์š”?