์ถ์ฒ
ChatGPT
์๋ฐ 8 ์์ค ์ฝ๋
TreeMap์ ์๋ฐ์์ ์ ๋ ฌ๋ ํค-๊ฐ ์์ ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ NavigableMap ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด์ด๋ค. TreeMap์ ๋ด๋ถ์ ์ผ๋ก ๋ ๋-๋ธ๋ ํธ๋ฆฌ(Red-Black Tree) ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํด ํค-๊ฐ์ ์ ์ฅํ๋ฉฐ, ์ด๋ฅผ ํตํด ์ฝ์ , ์ญ์ , ๊ฒ์ ๋ฑ์ ์ฐ์ฐ์ด O(log n) ์๊ฐ ๋ณต์ก๋๋ก ์ด๋ฃจ์ด์ง๋ค.
1. TreeMap์ ์ฃผ์ ํน์ง
์ ๋ ฌ๋ ์์
TreeMap์ ํญ์ ์ ๋ ฌ๋ ์ํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํค์ ์์ฐ ์์(Natural Ordering)์ ๋ฐ๋ผ ์ ๋ ฌ๋์ง๋ง, Comparator๋ฅผ ํตํด ์ฌ์ฉ์ ์ ์ ์ ๋ ฌ์ ์ ์ฉํ ์ ์๋ค.
๋ ๋-๋ธ๋ ํธ๋ฆฌ ๊ธฐ๋ฐ
๋ด๋ถ์ ์๋ก ๋ ๋-๋ธ๋ ํธ๋ฆฌ๋ผ๋ ์ด์ง ํ์ ํธ๋ฆฌ์ ๋ณํ์ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ค. ๋ ๋-๋ธ๋ ํธ๋ฆฌ๋ ์ฝ์ , ์ญ์ ์ ์๋์ผ๋ก ๊ท ํ์ ๋ง์ถ๊ธฐ ๋๋ฌธ์ ์ต์ ์ ๊ฒฝ์ฐ์๋ O(log n) ์ฑ๋ฅ์ ๋ณด์ฅํ๋ค.
์ค๋ณต๋ ํค ํ์ฉ ์ ํจ
TreeMap์ ์ค๋ณต๋ ํค๋ฅผ ํ์ฉํ์ง ์๋๋ค. ๋ง์ฝ ๋์ผํ ํค๊ฐ ์ฝ์ ๋๋ฉด, ๊ธฐ์กด ๊ฐ์ ๋ฎ์ด์ด๋ค.
Null ํค ๋ถํ
TreeMap์ null ํค๋ฅผ ํ์ฉํ์ง ์๋๋ค. ๋ง์ฝ null ํค๋ฅผ ์ฝ์ ํ๋ ค๊ณ ํ๋ฉด NullPointerException์ด ๋ฐ์ํ๋ค. ๋ค๋ง null ๊ฐ์ ํ์ฉ๋๋ค.
2. TreeMap์ ๋ด๋ถ ๊ตฌ์กฐ
TreeMap์ ๋ด๋ถ์ ์ผ๋ก TreeMap.Entry<K, V>๋ผ๋ ๋ ธ๋๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค. ๊ฐ ๋ ธ๋๋ ํธ๋ฆฌ ๊ตฌ์กฐ์์ ํ๋์ ํค-๊ฐ ์์ ๋ํ๋ด๋ฉฐ, ์ผ์ชฝ ์์๊ณผ ์ค๋ฅธ์ชฝ ์์, ๋ถ๋ชจ ๋ ธ๋, ๊ทธ๋ฆฌ๊ณ ์์ ์ ๋ณด(๋ ๋ ๋๋ ๋ธ๋)๋ฅผ ํฌํจํ๊ณ ์๋ค.
static final class Entry<K,V> implements Map.Entry<K,V> {
K key; // ํค
V value; // ๊ฐ
Entry<K,V> left; // ์ผ์ชฝ ์์ ๋
ธ๋
Entry<K,V> right; // ์ค๋ฅธ์ชฝ ์์ ๋
ธ๋
Entry<K,V> parent; // ๋ถ๋ชจ ๋
ธ๋
boolean color = BLACK; // ๋
ธ๋์ ์์ (RED ๋๋ BLACK)
// Entry ์์ฑ์
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
public K getKey() { return key; }
public V getValue() { return value; }
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}
์ฃผ์ ํ๋
- key : ํธ๋ฆฌ์์ ํค
- value : ํค์ ํด๋นํ๋ ๊ฐ
- left, right : ์ผ์ชฝ ๋ฐ ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋
- parent : ๋ถ๋ชจ ๋ ธ๋
- color : ๋ ๋-๋ธ๋ ํธ๋ฆฌ์์ ๋ ธ๋์ ์์(๋นจ๊ฐ ๋๋ ๊ฒ์ )
3. ๋ ๋ ๋ธ๋ ํธ๋ฆฌ๋?
๋ ๋ ๋ธ๋ ํธ๋ฆฌ(Red-Balck Tree)๋ ์๊ฐ ๊ท ํ ์ด์ง ํ์ ํธ๋ฆฌ์ ์ผ์ ์ผ๋ก, ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ๋ฐ๋ฅธ๋ค.
- ๊ฐ ๋ ธ๋๋ ๋นจ๊ฐ์(RED) ๋๋ ๊ฒ์ ์(BLACK) ์ค ํ๋์ ์์ ๊ฐ์ง๋ค.
- ๋ฃจํธ ๋ ธ๋๋ ํญ์ ๊ฒ์์์ด๋ค
- ๋ชจ๋ ๋ฆฌํ ๋ ธ๋(NIL)๋ ๊ฒ์์์ด๋ค.
- ๋นจ๊ฐ์ ๋ ธ๋์ ์์์ ๋ฐ๋์ ๊ฒ์์์ด๋ค.(์ฆ, ๋ ๊ฐ์ ๋นจ๊ฐ์ ๋ ธ๋๊ฐ ์ฐ์ํด ๋ํ๋ ์ ์๋ค.)
- ๋ฃจํธ์์ ๊ฐ ๋ฆฌํ ๋ ธ๋๊น์ง์ ๋ชจ๋ ๊ฒฝ๋ก๋ ๋์ผํ ์์ ๊ฒ์์ ๋ ธ๋๋ฅผ ๊ฐ์ง๋ค.(๊ท ํ ์กฐ๊ฑด)
์ด ๊ท์น์ ํตํด ํธ๋ฆฌ๊ฐ ๋ถ๊ท ํํ๊ฒ ์๋ผ๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ , ์ต์ ์ ๊ฒฝ์ฐ์๋ O(log n)์ ์ฑ๋ฅ์ ๋ณด์ฅํ๋ค.
4. TreeMap์ ์ฃผ์ ๋ฉ์๋ ๊ตฌํ
1. ์ฝ์ ์ฐ์ฐ put() ๋ฉ์๋
TreeMap์์ ์์๋ฅผ ์ฝ์ ํ ๋๋ ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ์ฝ์ ๊ท์น์ ๋ฐ๋ฅธ๋ค. ์์๋ฅผ ํธ๋ฆฌ์ ์ฝ์ ํ ํ, ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท์น์ ์๋ฐํ์ง ์๋๋ก ํธ๋ฆฌ๋ฅผ ์ฌ์กฐ์ (ํ์ ๋ฐ ์์ ๋ณ๊ฒฝ)ํ๋ค.
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
์ฃผ์ ๋์
- ํค ๋น๊ต : ์ฃผ์ด์ง ํค๋ฅผ ํธ๋ฆฌ์ ๊ธฐ์กด ํค๋ค๊ณผ ๋น๊ตํ๋ค. ๋น๊ต๋ ์์ฐ ์์๋ Comparator๋ฅผ ์ฌ์ฉํ๋ค.
- ์ฝ์ ์์น ๊ฒฐ์ : ์ ํค์ ์์น๊ฐ ๊ฒฐ์ ๋๋ฉด ํธ๋ฆฌ์ ์ฝ์ ๋๋ค.
- ํธ๋ฆฌ ์ฌ์กฐ์ : ์ฝ์ ํ ํธ๋ฆฌ์ ๊ท ํ์ ๋ง์ถ๊ธฐ ์ํด ํ์ ๊ณผ ์์ ๋ณ๊ฒฝ ์์ ์ด ์ด๋ฃจ์ด์ง๋ค. ์ด๋ fixAfterInsertion() ๋ฉ์๋์์ ์ํ๋๋ค.
2. ๊ฒ์ ์ฐ์ฐ get() ๋ฉ์๋
TreeMap์์ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ ๋๋ ์ด์ง ํ์์ ์ฌ์ฉํ๋ค. ์ฃผ์ด์ง ํค์ ํธ๋ฆฌ์ ๊ฐ ๋ ธ๋์ ํค๋ฅผ ๋น๊ตํด ๊ฒ์ํ๋ค.
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p == null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
์ฃผ์ ๋์
- ํค ๋น๊ต : ๊ฒ์ํ ํค๋ฅผ ํธ๋ฆฌ์ ๊ฐ ๋ ธ๋์ ํค์ ๋น๊ตํ๋ฉฐ ์ผ์ชฝ ๋๋ ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋๋ก ์ด๋ํ๋ค.
- ํค ๋ฐ๊ฒฌ : ์ฃผ์ด์ง ํค๋ฅผ ์ฐพ์ผ๋ฉด ํด๋น ํค์ ๋งคํ๋ ๊ฐ์ ๋ฐํํ๋ค. ์ฐพ์ง ๋ชปํ ๊ฒฝ์ฐ null์ ๋ฐํํ๋ค.
3. ์ญ์ ์ฐ์ฐ remove() ๋ฉ์๋
TreeMap์์ ๋ ธ๋๋ฅผ ์ญ์ ํ ๋๋ ํธ๋ฆฌ์ ๊ตฌ์กฐ๋ฅผ ์ ์งํ๊ธฐ ์ํด ์ฌ๋ฌ ๊ฐ์ง ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ค.
- ์์์ด ์๋ ๋ ธ๋ : ๋จ์ํ ๋ ธ๋๋ฅผ ์ ๊ฑฐ
- ํ๋์ ์์์ด ์๋ ๋ ธ๋ : ์์์ ๋ถ๋ชจ ๋ ธ๋์ ์ฐ๊ฒฐ
- ๋ ๊ฐ์ ์์์ด ์๋ ๋ ธ๋ : ์ค์ ํ์์(successor) ๋ ธ๋๋ก ๊ต์ฒดํ ํ, ํ์์๋ฅผ ์ญ์
์ญ์ ํ์๋ ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท์น์ ์ ์งํ๊ธฐ ์ํด ํธ๋ฆฌ๋ฅผ ์ฌ์กฐ์ ํ๋ค.
public V remove(Object key) {
Entry<K,V> p = getEntry(key);
if (p == null)
return null;
V oldValue = p.value;
deleteEntry(p);
return oldValue;
}
private void deleteEntry(Entry<K,V> p) {
modCount++;
size--;
if (p.left != null && p.right != null) {
Entry<K,V> s = successor(p);
p.key = s.key;
p.value = s.value;
p = s;
}
Entry<K,V> replacement = (p.left != null ? p.left : p.right);
if (replacement != null) {
replacement.parent = p.parent;
if (p.parent == null)
root = replacement;
else if (p == p.parent.left)
p.parent.left = replacement;
else
p.parent.right = replacement;
p.left = p.right = p.parent = null;
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) {
root = null;
} else {
if (p.color == BLACK)
fixAfterDeletion(p);
if (p.parent != null) {
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
p.parent = null;
}
}
}
์ฃผ์ ๋์
- ๋ ธ๋ ์ญ์ : ์ญ์ ํ ๋ ธ๋๋ฅผ ์ฐพ๊ณ , ์์ ๋ ธ๋์ ์์ ๋ฐ๋ผ ํธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ ์งํ๋ฉด์ ์ญ์
- ํธ๋ฆฌ ์ฌ์กฐ์ : ์ญ์ ํ ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท ํ์ ์ ์งํ๊ธฐ ์ํด fixAfterDeletion() ๋ฉ์๋์์ ํธ๋ฆฌ๋ฅผ ์ฌ์กฐ์ ํ๋ค.
5. ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท ํ ์ ์ง (ํ์ ๋ฐ ์์ ๋ณ๊ฒฝ)
์ฝ์ ๊ณผ ์ญ์ ํ ํธ๋ฆฌ์ ๊ท ํ์ ๋ง์ถ๊ธฐ ์ํด ํ์ ๊ณผ ์์ ๋ณ๊ฒฝ ์์ ์ด ์ด๋ฃจ์ด์ง๋ค. TreeMap์ ๋ด๋ถ์์๋ fixAfterInsertion()๊ณผ fixAfterDeletion() ๋ฉ์๋๋ฅผ ํตํด ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท์น์ ์ ์งํ๋ค.
- ํ์ : ์ฝ์ ๋๋ ์ญ์ ๋ก ์ธํ ํธ๋ฆฌ๊ฐ ๋ถ๊ท ํํด์ง๋ฉด, ์ผ์ชฝ ๋๋ ์ค๋ฅธ์ชฝ์ผ๋ก ํ์ ํด ํธ๋ฆฌ์ ๊ท ํ์ ๋ง์ถ๋ค.
- ์์ ๋ณ๊ฒฝ : ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ท์น์ ๋ฐ๋ผ ๋ ธ๋์ ์์์ ๋ณ๊ฒฝํด ํธ๋ฆฌ์ ๊ท ํ์ ์ ์งํ๋ค.
6. TreeMap์ ์ฑ๋ฅ
- ์๊ฐ ๋ณต์ก๋ : TreeMap์ ๋ชจ๋ ์ฐ์ฐ(์ฝ์ , ์ญ์ , ๊ฒ์)์ O(log n) ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ค. ์ด๋ ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ์๊ฐ ๊ท ํ ํน์ฑ ๋๋ถ์ด๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ: TreeMap์ ๊ฐ ๋ ธ๋๊ฐ ์ถ๊ฐ์ ์ธ ์์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฏ๋ก HashMap๋ณด๋ค ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ค์ ๋์ ์ ์๋ค.
๊ฒฐ๋ก
TreeMap์ ๋ ๋-๋ธ๋ ํธ๋ฆฌ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌํ๋ ์ ๋ ฌ๋ ๋งต์ผ๋ก, ์ฝ์ , ์ญ์ , ๊ฒ์ ๋ฑ์์ O(log n) ์ฑ๋ฅ์ ๋ณด์ฅํฉ๋๋ค. ํญ์ ์ ๋ ฌ๋ ์ํ๋ฅผ ์ ์งํด์ผ ํ๊ฑฐ๋, ๋ฒ์ ๊ฒ์์ด ์์ฃผ ํ์ํ ๋ ๋งค์ฐ ์ ์ฉํ ์๋ฃ๊ตฌ์กฐ์ด๋ค.
'๋น ๊ตฌ๋ฉ ์ฑ์ฐ๊ธฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Java] Queue ์ธํฐํ์ด์ค (1) | 2024.09.14 |
---|---|
[๋์์ธ ํจํด][Java] ์์ฐ์-์๋น์ ํจํด Producer-Consumer Pattern (0) | 2024.09.14 |
[Java] NavigableMap (0) | 2024.09.14 |
[Java] ์์ฐ ์์ Natural Ordering (0) | 2024.09.11 |
[Java] SortedMap (0) | 2024.09.11 |