[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