Collection
List Interface
Set Interface
Map Interface
Java์ Collection๋ ๋ฐ์ดํฐ์ ์งํฉ, ๊ทธ๋ฃน์ ์๋ฏธํ๋ค.
Java Collections Framework(JCF)
๋ Collection๊ณผ ์ด๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ํด๋์ค๋ฅผ ์ ์ํ๋ interface๋ฅผ ์ ๊ณตํ๋ค.- Collection Interface๋ ํฌ๊ฒ
List
,Set
,Queue
3๊ฐ์ง๋ก ๋ถ๋ฅ๋๋ค. Map
์ธํฐํ์ด์ค๋ Collection ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ์ง ์์ง๋ง Collection์ผ๋ก ๋ถ๋ฅํ๋ค.
์ปฌ๋ ์ | ํน์ง |
---|---|
ArrayList | ๋ฐฐ์ด๊ธฐ๋ฐ, ๋ฐ์ดํฐ์ ์ถ๊ฐ์ ์ญ์ ์ ๋ถ๋ฆฌ, ์์ฐจ์ ์ธ ์ถ๊ฐ/์ญ์ ๋ ์ ์ผ ๋น ๋ฆ, ์์์ ์์์ ๋ํ ์ ๊ทผ์ฑ์ด ๋ฐ์ด๋จ |
Linked List | ์ฐ๊ฒฐ๊ธฐ๋ฐ, ๋ฐ์ดํฐ์ ์ถ๊ฐ์ ์ญ์ ์ ์ ๋ฆฌ, ์์์ ์์์ ๋ํ ์ ๊ทผ์ฑ์ด ์ข์ง ์๋ค. |
HashMap | ๋ฐฐ์ด๊ณผ ์ฐ๊ฒฐ์ด ๊ฒฐํฉ๋ ํํ, ์ถ๊ฐ/์ญ์ /๊ฒ์/์ ๊ทผ์ฑ์ด ๋ชจ๋ ๋ฐ์ด๋จ, ๊ฒ์์๋ ์ต๊ณ ์ฑ๋ฅ์ ๋ณด์ธ๋ค. |
TreeMap | ์ฐ๊ฒฐ๊ธฐ๋ฐ, ์ ๋ ฌ๊ณผ ๊ฒ์(ํนํ ๋ฒ์๊ฒ์)์ ์ ํฉ, ๊ฒ์ ์ฑ๋ฅ์ HashMap ๋ณด๋ค ๋จ์ด์ง๋ค. |
HashSet | ๋ด๋ถ์ ์ผ๋ก HashMap์ ์ด์ฉํด์ ๊ตฌํ |
TreeSet | ๋ด๋ถ์ ์ผ๋ก TreeMap์ ์ด์ฉํด์ ๊ตฌํ |
LinkedHashMap | HashMap์ ์ ์ฅ์์ ์ ์ง๊ธฐ๋ฅ์ ์ถ๊ฐ |
LinkedHashSet | HashSet์ ์ ์ฅ์์ ์ ์ง๊ธฐ๋ฅ์ ์ถ๊ฐ |
Collections ํด๋์ค
๋ ๋ชจ๋ ์ปฌ๋ ์
์ ์๊ณ ๋ฆฌ์ฆ์ ๋ด๋นํ๋ค.
- ์ ํธ๋ฆฌํฐ ํด๋์ค๋ก์จ static ๋ฉ์๋๋ก ๊ตฌ์ฑ๋์ด ์๊ณ ์ปฌ๋ ์ ๋ค์ ์ปจํธ๋กคํ๋๋ฐ์ ์ฌ์ฉ๋๋ค.
- ์ฃผ์ํ ์ ์ ์๋ฐ์ Collection์ ์ธํฐํ์ด์ค์ด๋ฉฐ, Collections๋ ํด๋์ค๋ผ๋ ์ ์ด๋ค.
๋ํ์ ์ธ ๋ฉ์๋
- ์ ๋ ฌ(Sorting) : ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์์๊ฐ ์ค๋ฆ์ฐจ์์ด ๋๋๋ก ๋ฆฌ์คํธ๋ฅผ ์ฌ์ ๋ ฌํจ
- ์ ํ๋ง(Shuffling) : ์ ํ๋ง ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค์ผ๋ก ๋ชฉ๋ก์ ์ฌ์ ๋ ฌํจ (์ฐ์ฐํ ๊ฒ์์ ๊ตฌํํ ๋ ์ ์ฉ)
- ํ์ (Searching) : ์ด์ง ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ์ ๋ ฌ๋ ๋ชฉ๋ก์์ ์ง์ ๋ ์์๋ฅผ ๊ฒ์
List
๋ ์์๊ฐ ์๋ ๋ฐ์ดํฐ์ ์งํฉ์ด๋ค.
- List Interface์ ๊ตฌํ ํด๋์ค์๋
Vector
,ArrayList
,LinkedList
๊ฐ ์๋ค. - List์ index์๋ ๋ฐ์ดํฐ์ ์ฃผ์๊ฐ(์ฐธ์กฐ๊ฐ)์ด ๋ค์ด์๋ค.
- ๋ฐ์ดํฐ ์์ฒด๋ฅผ ์ ์ฅํ์ง ์๊ณ ์ฃผ์๋ฅผ ์ฐธ์กฐํ๋ค
null
์ด ์ ์ฅ๋ ๊ฒฝ์ฐ ํด๋น index์๋ ์ฐธ์กฐ๊ฐ ์กฐ์ฐจ ๋ค์ด์์ง ์๋ค.
- ๋ฐ์ดํฐ์ ์ค๋ณต์ ํ์ฉํ๋ค
- List ์ ์ค๋ณต๋ ๋ฐ์ดํฐ๋ ๋ชจ๋ ๋์ผํ ์ฃผ์๊ฐ์ ์ฐธ์กฐํ๋ค
List<String> list = new ArrayList<>(Arrays.asList(1, 2, 3));
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)
์ ์๊ฐ๋ณต์ก๋๋ก ์กฐํํ ์ ์๋ค
- index๋ฅผ ํตํด
์ฝ์ /์ญ์
- ๋ด๋ถ์ ์ผ๋ก Object ๋ฐฐ์ด๋ก ๊ตฌ์ฑ๋์ด์์ผ๋ฏ๋ก ์ค๊ฐ ๋๋ ๋งจ ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
, ์ญ์ ํ ๋ ์ต์
์ ๊ฒฝ์ฐ
O(N)
์ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค - ์ถ๊ฐํ๋ ค๋ ๋ฐ์ดํฐ์ ์์น๊ฐ ๋งจ ๋ค์ด๊ณ , Object ๋ฐฐ์ด์ ๊ฐ์ฉ ๊ณต๊ฐ์ด ์๋ค๋ฉด
O(1)
์ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค
- ๋ด๋ถ์ ์ผ๋ก Object ๋ฐฐ์ด๋ก ๊ตฌ์ฑ๋์ด์์ผ๋ฏ๋ก ์ค๊ฐ ๋๋ ๋งจ ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
, ์ญ์ ํ ๋ ์ต์
์ ๊ฒฝ์ฐ
List<E> list = new Vector<>();
Vector
๋ ArrayList์ ๋์ผํ ๊ธฐ๋ฅ์ ์ํํ๋ ํด๋์ค์ด๋ค.
- ๋ด๋ถ์์ ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ArrayList๋ณด๋ค ์๋์ ์ผ๋ก ์ฑ๋ฅ์ด ์ข์ง ์๋ค
- ๊ธฐ์กด ์ฝ๋์ ํธํ์ฑ์ ์ํด ๋จ์์๋ค
ArrayList์ Vector์ ์ฐจ์ด์
- ArrayList๋ ์๋์ผ๋ก ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์๊ธฐ ๋๋ฌธ์ Thread Safe ํ์ง ์๋ค.
- Vector๋ Thread์ ์์ ์๊ด์์ด ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ๋๋ฌธ์ Thread Safe ํ์ง๋ง ์ฑ๊ธ ์ค๋ ๋ ํ๊ฒฝ์์ ์กฐ์ฐจ ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํ๋ฏ๋ก ArrayList์ ๋นํด ์ฑ๋ฅ์ด ์ข์ง ์๋ค
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)
์ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค
- first ํฌ์ธํฐ๋ถํฐ ํ๊ฒ ๋ฐ์ดํฐ๊น์ง ์์ฐจ์ ์ผ๋ก ํ์ํด์ผํ๊ธฐ ๋๋ฌธ์ ์ต์
์ ๊ฒฝ์ฐ
์ฝ์ /์ญ์
- ๋๋จธ์ง ๋ฐ์ดํฐ๋ฅผ shiftํ ํ์ ์์ด ์ฝ์
/์ญ์ ํ ๋ฐ์ดํฐ(๋
ธ๋)์ ํฌ์ธํฐ๋ง ์์ ํ๋ฉด ๋๋ค. (
O(1)
) ํ์ง๋ง ์ฝ์ /์ญ์ ํ๋ ค๋ ๋ฐ์ดํฐ์ ์์น๊ฐ ์ค๊ฐ์ ์๋ค๋ฉด ํ์ํด์ผํ๊ธฐ ๋๋ฌธ์ ์ต์ ์ ๊ฒฝ์ฐO(N)
์ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค.
- ๋๋จธ์ง ๋ฐ์ดํฐ๋ฅผ shiftํ ํ์ ์์ด ์ฝ์
/์ญ์ ํ ๋ฐ์ดํฐ(๋
ธ๋)์ ํฌ์ธํฐ๋ง ์์ ํ๋ฉด ๋๋ค. (
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
์ด๋ ์์๋ฅผ ์ ์งํ์ง ์๋ ๋ฐ์ดํฐ์ ์งํฉ์ด๋ค.
- Set Interface์ ๊ตฌํ ํด๋์ค๋ก
HashSet
,TreeSet
์ด ์๋ค. - Set์ index ๊ฐ๋
์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ํ์ํ๋ ค๋ฉด iterator๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
Iterator<String> iter = set.iterator();
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 ? e2==null : 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()
๋ฉ์๋๋ก ๋๋ฑ๋น๊ต๋ฅผ ์ํํ์ฌ ๋๋ฑ ๊ฐ์ฒด์ธ์ง ํ๋ณํ๋ค. (๋๋ฑ ๋น๊ต๋ ๊ฐ์ฒด๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ฐ์ดํฐ์ ๊ฐ ์์ฒด๋ฅผ ๋น๊ตํ๋ ๊ฒ์ด๋ค)
์ด์ฒ๋ผ HashMap์ key-value์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ ์ ๊ฐ์ฒด์ key๊ฐ(hashCode() ๋ฐํ ๊ฐ
)์ ๋ณด๊ณ ๊ธฐ์กด์ ๋ฐ์ดํฐ์ ๋น๊ตํ๋ค. ๋ง์ฝ hashCode() ๋ฐํ ๊ฐ์ด ๊ฐ์ ๊ธฐ์กด์ ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ๋ค๋ฉด, equals()
๋ฉ์๋๋ก ๋๋ฑ ๋น๊ต๋ฅผ ํ๋ฒ ๋ ์ํํ๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋์ผํ๋ค๋ฉด HashMap์ ํด๋น ๊ฐ์ฒด๋ฅผ ์ ์ฅํ์ง ์๋๋ค.
์ด์ ๊ฐ์ ์ด์ ๋ก HashSet์ ์ค๋ณต ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์๋ค.
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
์ key-value ์์ผ๋ก ์ด๋ฃจ์ด์ง ๋ฐ์ดํฐ(Map.Entry)์ ์งํฉ์ด๋ค.
- Map Interface์ ๊ตฌํ ํด๋์ค์๋
HashMap
,HashTable
,TreeMap
๋ฑ์ด ์๋ค - Map์ key์ ์ค๋ณต์ ํ์ฉํ์ง ์๊ณ , value์ ์ค๋ณต์ ํ์ฉํ๋ค. (๊ธฐ์กด์ ์ ์ฅ๋ key์ ์๋ก์ด value2๋ฅผ ์ ์ฅํ๋ฉด ๊ธฐ์กด์
value1
์ด ์๋ก์ดvalue2
๋ก ๋์ฒด๋๋ค) - ๋ฐ์ดํฐ(Map.Entry)์ ์์๊ฐ ์ ์ง๋์ง ์๋๋ค
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;
...
}
- 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<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์ ์ฌ์ด์ฆ๋ ์ธ์ ๋๋ฆฌ๋์?