[Algorithm] ์๋ฐ์คํฌ๋ฆฝํธ Map์ผ๋ก ๊ตฌํํ๋ LRU Cache ์๊ณ ๋ฆฌ์ฆ
LRU ์บ์ ํน์ง
์บ์(Cache)๋ ๋ฐ์ดํฐ๋ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ผ์์ ์ผ๋ก ์ ์ฅํ๋ ๊ฒ์ ๊ฐ๋ฆฌํจ๋ค. ์์ฃผ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ ์ฐ์ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๋ณด๊ดํด์ ๋์ผํ ์ ๋ณด๋ฅผ ์์ฒญ๋ฐ์์ ๋ ๋ ๋น ๋ฅธ ์๋๋ก ์ ๊ณตํ ์ ์๋ค.
LRU ์บ์๋ ๋ํ์ ์ธ ์บ์ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๋ก ์ ํ๋ ์ ์ฅ ๊ณต๊ฐ์ ๊ด๋ฆฌํ๊ธฐ ์ํด ๊ฐ์ฅ ์ค๋์ ์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ค. LRU๋ Least Recently Used์ ์ฝ์๋ก ์ฌ์ฉํ์ง ๊ฐ์ฅ ์ค๋๋ ์ ๋๋ก ํด์ํ ์ ์๋ค.
LRU ์บ์์์ ์กฐํ/์ฐ๊ธฐ์ ํด๋น ๊ฐ์ ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ ๊ฒ์ผ๋ก ์ฒ๋ฆฌํ๋๊ฒ ํต์ฌ์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ Map ๋ฑ์ ์ด์ฉํด์ ๊ตฌํํ ๋ ๊ฐ์ด ๋ค์ ์์นํ ์๋ก ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ ๊ฒ์ผ๋ก ํ์ํ๋ค.
- ์กฐํ : ์บ์์ ๊ฐ์ด ์กด์ฌํ๋ฉด ํด๋น ๊ฐ์ ์บ์ ๋ง์ง๋ง(์ต์ )์ผ๋ก ์ด๋์ํจ๋ค
- ์ฐ๊ธฐ :
- ์บ์์ ๊ฐ์ด ์กด์ฌํ๋ฉด ๊ธฐ์กด ๊ฐ์ ์ญ์ ํ๊ณ , ์บ์ ๋ง์ง๋ง์ ๊ธฐ์กด ๊ฐ์ ์ถ๊ฐํ๋ค
- ์บ์๊ฐ ๊ฐ๋ ์ฐผ๋ค๋ฉด ๊ฐ์ฅ ์ค๋๋ ์์ชฝ ๊ฐ์ ์ ๊ฑฐํ๊ณ , ์บ์ ๋ง์ง๋ง์ ์๋ก์ด ๊ฐ์ ์ถ๊ฐํ๋ค
LRU ์บ์ ๊ตฌํ
class LRUCache {
constructor(capacity) {
/** ์บ์ ์ต๋ ์ฉ๋ ์ค์ */
this.capacity = capacity;
/** ์ฝ์
์์๋ฅผ ๊ธฐ์ตํ๋ Map์ผ๋ก ์บ์ ๊ด๋ฆฌ, ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ key๊ฐ ๋ค์ ์์น */
this.cache = new Map();
}
/**
* ์ฃผ์ด์ง key์ ํด๋นํ๋ ๊ฐ์ ์บ์์์ ๊ฐ์ ธ์ค๋ ๋ฉ์๋
* ๊ฐ์ด ์กด์ฌํ๋ฉด key๋ฅผ ์บ์์ ๋์ผ๋ก ์์น์์ผ์ ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ ๊ฒ์ผ๋ก ํ์ (LRU ์บ์ ํน์ง)
*/
get(key) {
if (!this.cache.has(key)) return -1;
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value); // ์กฐํํ key๋ฅผ ์บ์ ๊ฐ์ฅ ๋ง์ง๋ง์ ์์น ์ํด
return value;
}
/**
* ์๋ก์ด key-value ์์ ์บ์์ ์ถ๊ฐํ๋ ๋ฉ์๋
* key๊ฐ ์กด์ฌํ๋ฉด ํด๋น key๋ฅผ ์ญ์ ํ๊ณ ์บ์ ๋ง์ง๋ง์ ์ ํญ๋ชฉ์ผ๋ก ์ถ๊ฐ
* ์บ์๊ฐ ๊ฐ๋ ์ฐผ๋ค๋ฉด, ๊ฐ์ฅ ์ค๋๋ ์์ชฝ key๋ฅผ ์ ๊ฑฐํ๊ณ , ์บ์ ๋ง์ง๋ง์ ์ ํญ๋ชฉ ์ถ๊ฐ
*/
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key); // key๊ฐ ์ด๋ฏธ ์กด์ฌํ๋ฉด ์ญ์
} else if (this.cache.size === this.capacity) {
const oldestKey = this.cache.keys().next().value; // this.cache์ ์ฒซ๋ฒ์งธ ๊ฐ(์ฌ์ฉํ์ง ๊ฐ์ฅ ์ค๋๋ key)
this.cache.delete(oldestKey);
}
this.cache.set(key, value); // ์ ํญ๋ชฉ์ ์บ์ ๋ง์ง๋ง์ ์ถ๊ฐ
}
}
ํ๋กํผํฐ
this.capacity
ํ๋กํผํฐ๋ฅผ ํตํด ์บ์๊ฐ ๋ณด๊ดํ ์ ์๋ ํญ๋ชฉ์ ์๋ฅผ ์ ํํ๋ค. ์ด ๊ฐ์ ์ด๊ณผํ ๊ฒฝ์ฐ ์บ์์ ๊ฐ์ฅ ์ค๋๋ ํญ๋ชฉ์ ์ ๊ฑฐํ์ฌ ์ ํญ๋ชฉ์ ์ ์ฅํ ๊ณต๊ฐ์ ๋ง๋ ๋ค.
์บ์ ๋ฐ์ดํฐ this.cache
๋ ์ฝ์
์์๋ฅผ ๊ธฐ์ตํ๋ Map
์ผ๋ก ๊ด๋ฆฌํ๋ค. LRU ์บ์์์ ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ ํค๋ Map ๋ท๋ถ๋ถ์ ์์น์ํจ๋ค. ์ ํญ๋ชฉ์ ์บ์์ ์ถ๊ฐํ๊ฑฐ๋ ๊ธฐ์กด ํญ๋ชฉ์ ๋ค์ ์ฌ์ฉํ ๋, ํด๋น ํญ๋ชฉ์ Map ๋ท๋ถ๋ถ์ผ๋ก ์ด๋ํ์ฌ ์ต๊ทผ ์ฌ์ฉํจ์ผ๋ก ๋ํ๋ธ๋ค.
Get
์บ์์์ ์ฃผ์ด์ง key์ ํด๋นํ๋ ๊ฐ์ ๊ฐ์ ธ์ค๋ ๋ฉ์๋. ์กฐํํ key๊ฐ ์บ์์ ์กด์ฌํ์ง ์์ผ๋ฉด -1
์ ๋ฐํํ๊ณ , ์กด์ฌํ๋ค๋ฉด ํด๋น key๋ฅผ ์บ์ ๋ง์ง๋ง์ ์์น์์ผ์ ์ต๊ทผ์ ์ฌ์ฉํ ๊ฒ์ผ๋ก ํ์ํ๋ค.
Set
์๋ก์ด key-value ์์ ์บ์์ ์ถ๊ฐํ๋ ๋ฉ์๋. ์บ์์ ์ด๋ฏธ key๊ฐ ์กด์ฌํ๋ค๋ฉด ๊ธฐ์กด key๋ฅผ ์ญ์ ํ๊ณ ์บ์ ๋ง์ง๋ง์ ์ ํญ๋ชฉ์ผ๋ก ์ถ๊ฐํ๋ค. ์บ์๊ฐ ๊ฐ๋ ์ฐผ๋ค๋ฉด ์ฌ์ฉํ์ง ๊ฐ์ฅ ์ค๋๋ ์์ชฝ key๋ฅผ ์ ๊ฑฐํ๊ณ , ์บ์ ๋ง์ง๋ง์ ์ ํญ๋ชฉ์ ์ถ๊ฐํ๋ค.
์ดํฐ๋ ์ดํฐ โญ
์ฌ๊ธฐ์ ์ฃผ๋ชฉํ ์ ์ ๊ฐ์ฅ ์ค๋๋ key๋ฅผ ๊ฐ์ ธ์ฌ ๋ ์ฌ์ฉํ next()
๋ฉ์๋๋ค. this.cache.keys()
๋ฅผ ํธ์ถํ๋ฉด ์บ์ ํค๋ค์ ์ํํ ์ ์๋ ์ดํฐ๋ ์ดํฐ๋ฅผ ๋ฐํํ๋ค. ๐ ๋ฐฐ์ด์์ Symbol.iterator
ํ๋กํผํฐ์ ์ ๊ทผํด์ ํธ์ถํ๋ฉด ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ์ป์ ์ ์๋ค.
const cache = new Map();
cache.set('a', 1);
cache.set('b', 2);
cache.set('c', 3);
cache.keys(); // MapIterator {'a', 'b', 'c'}
Symbol.iterator
๋ฉ์๋๊ฐ ๊ตฌํ๋์ด ์๋ ๊ฐ์ฒด๋ฅผ ์ดํฐ๋ฌ๋ธ ๊ฐ์ฒด๋ผ๊ณ ๋ถ๋ฅด๋๋ฐ, ๋ฐฐ์ด / ๋ฌธ์์ด / Map / Set ๋ฑ์ด ๋ํ์ ์ธ ์ดํฐ๋ฌ๋ธ์ด๋ค. Symbol.iterator
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ณ , ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด ์์๋ next()
๋ฉ์๋๊ฐ ๊ตฌํ๋์ด ์๋ค.
next()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด value
, done
ํ๋กํผํฐ๋ฅผ ๊ฐ๋ ์ดํฐ๋ ์ดํฐ ๋ฆฌ์ ํธ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. value
๋ ํ์ฌ ์ํ์ค์ธ ์ดํฐ๋ฌ๋ธ์ ๊ฐ์ด๊ณ , done
์ ๋ฐ๋ณต ์ข
๋ฃ ์ฌ๋ถ๋ฅผ ๋ํ๋ธ๋ค.
์ด๋ฌํ ํน์ฑ ๋๋ฌธ์ next()
๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค value
ํ๋กํผํฐ๋ฅผ ํตํด ๊ฐ์ ์์ฐจ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๋ค. for of
๋ฌธ์ผ๋ก ๊ฐ์ ์ํํ ๋๋ ๋ด๋ถ์ ์ผ๋ก next()
๋ฉ์๋๋ฅผ ํธ์ถํด์ value
๊ฐ์ ๊ฐ์ ธ์ค๋ ๊ฒ.
const array = [1, 2, 3]; // ๋ฐฐ์ด์ ์ดํฐ๋ฌ๋ธ ํ๋กํ ์ฝ์ ์ค์ํ ์ดํฐ๋ฌ๋ธ์ด๋ค
const iterator = array[Symbol.iterator](); // next ๋ฉ์๋๋ฅผ ๊ฐ๋ ์ดํฐ๋ ์ดํฐ ๊ฐ์ฒด ๋ฐํ
// next() ๋ฉ์๋๊ฐ ๋ฐํํ๋ ์ดํฐ๋ ์ดํฐ ๋ฆฌ์ ํธ ๊ฐ์ฒด๋ value์ done ํ๋กํผํฐ๋ฅผ ๊ฐ๋๋ค
iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
iterator.next(); // { value: undefined, done: true }
this.cache.keys()
๊ฐ ๋ฐํํ๋ ์ดํฐ๋ ์ดํฐ์ ํ๋กํ ํ์
์ ์ดํด๋ณด๋ฉด next()
๋ฉ์๋๊ฐ ๊ตฌํ๋ผ ์๋ค. ์์ ๋ง์ฐฌ๊ฐ์ง๋ก next()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ์ดํฐ๋ ์ดํฐ ๋ฆฌ์ ํธ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ณ , ์ด ๊ฐ์ฒด์ value
ํ๋กํผํฐ๋ฅผ ํตํด ์ํ์ค์ธ ์ดํฐ๋ฌ๋ธ์ ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
const iterator = cache.keys();
iterator.next(); // {value: 'a', done: false}
iterator.next(); // {value: 'b', done: false}
iterator.next(); // {value: 'c', done: false}
iterator.next(); // {value: undefined, done: true}
์์์ ๊ตฌํํ LRU Cache
์์ put
๋ฉ์๋์ ์๋ this.cache.keys().next()
๋ฅผ 1ํ ํธ์ถ ํ์ผ๋ฏ๋ก next().value
๋ ๊ฐ์ฅ ์ค๋๋ ๊ฐ์ ๊ฐ๋ฆฌํค๋, this.cache
์ ์ฒซ๋ฒ์งธ ์์๋ฅผ ๊ฐ์ ธ์จ๋ค.
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[React] ๋ฆฌ์กํธ์์ setTimeout ๋ ํธํ๊ฒ ์ฐ๊ธฐ
[React] ๋ฆฌ์กํธ์์ setTimeout ๋ ํธํ๊ฒ ์ฐ๊ธฐ
2024.05.28 -
[React] ํฌ๋กฌ ํ์ฅ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ ๋ฐฐ๊ฒฝ ์ง์ ๋ฐ ํํ ๋ฆฌ์ผ
[React] ํฌ๋กฌ ํ์ฅ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ ๋ฐฐ๊ฒฝ ์ง์ ๋ฐ ํํ ๋ฆฌ์ผ
2024.05.28 -
[Algorithm] ์ต์ ํ(Heap)์ผ๋ก ์ฐ์ ์์ ํ ๊ตฌํํ๊ธฐ
[Algorithm] ์ต์ ํ(Heap)์ผ๋ก ์ฐ์ ์์ ํ ๊ตฌํํ๊ธฐ
2024.05.28 -
[Algorithm] ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ — ์ต๋จ ๊ฒฝ๋ก ์ฐพ๊ธฐ
[Algorithm] ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ — ์ต๋จ ๊ฒฝ๋ก ์ฐพ๊ธฐ
2024.05.28