๊ด€๋ฆฌ ๋ฉ”๋‰ด

Daehyunii's Dev-blog

19 ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋ณธ๋ฌธ

๐Ÿ“š Language & CS knowledge/Algorithm & Data structure

19 ํ•ด์‹œ ํ…Œ์ด๋ธ”

Daehyunii 2022. 8. 16. 20:17

19.1 ํ•ด์‹œ ํ…Œ์ด๋ธ”(ํ•ด์‹œ ๋งต)

  ํ•ด์‹œ ํ…Œ์ด๋ธ”์ด๋ž€ ํ‚ค์™€ ๊ฐ’์„ ์Œ์œผ๋กœ ์ €์žฅํ•˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๋งํ•œ๋‹ค. ๋งŽ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ๋‚ด์žฅ๋˜์–ด ์žˆ๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์ด๋‹ค. python์€dictionaries, Java Script๋Š” Object์™€ Maps, Java๋Š” Go, Scala ๊ทธ๋ฆฌ๊ณ  Maps, Juby๋Š” Hashes๋กœ ์•Œ๋ ค์ ธ ์žˆ๋‹ค. ์ด ์ฒ˜๋Ÿผ ์–ธ์–ด๋งˆ๋‹ค ํ•ด์‹œ ํ…Œ์ด๋ธ”์ด ๋‚ด์žฅ๋˜์–ด ์žˆ๊ณ  ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ์ถ”์ƒ์ ์ธ ๊ฐœ๋…์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฝ”๋”ฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ์ผ๋ฐ˜์ ์ธ ๋ฐฐ์—ด๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค. ๋ฐฐ์—ด์€ ์ธ๋ฑ์Šค๋ฅผ ๊ฐ€์ง€์ง€๋งŒ ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ์ˆœ์„œ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค. ํ•ด์‹œ ํ…Œ์ด๋ธ”์ด ์ข‹์€ ์ด์œ ๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š”๋ฐ ์•„์ฃผ ๋น ๋ฅด๊ณ  ๋ฐ์ดํ„ฐ ๊ทธ ์ž์ฒด๊ฐ€ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋ฐฉ๋ฒ•์— ๋”ฐ๋ผ ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด ํŽธํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

 

19.2 ํ•ด์‹œ ํ•จ์ˆ˜

  ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ์ž„์˜์˜ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ •ํ•ด์ง„ ํฌ๊ธฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ฆ‰, ์ž…๋ ฅ๊ฐ’์„ ์ธก์ •ํ•ด์„œ ์ •ํ•ด์ง„ ํฌ๊ธฐ์˜ ์ถœ๋ ฅ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ผ์ •ํ•œ ๊ธฐ์ค€์„ ์ •ํ•ด์„œ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๋ฐ, ๊ทธ๊ฒŒ ๋งค์šฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์—ฐ๊ตฌํ•˜๋Š” ๋งŽ์€ ์—ฐ๊ตฌ์ง„๋“ค์ด ์žˆ๋‹ค. ๋‚ด๊ฐ€ ๊ณต๋ถ€ํ•œ ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด์‹œ ํ•จ์ˆ˜์— ๋„ฃ์œผ๋ฉด ์ผ์ •ํ•˜๊ฒŒ ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐฐ์—ด์— [ํ‚ค,๊ฐ’] ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด์„œ ์ €์žฅํ•œ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ํ•ด์‹œ ํ•จ์ˆ˜์— ํ•„์š”ํ•œ ์ •๋ณด์˜ ํ‚ค๋ฅผ ๋„ฃ์œผ๋ฉด ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ์•Œ๋ ค์ฃผ๊ณ  ๊ทธ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐฐ์—ด์—์„œ ์ •๋ณด๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ•ด์‹œ ํ•จ์ˆ˜์˜ ์—ญํ• ์ด๋‹ค.

 

โ€ปํ•ด์‹œ ํ•จ์ˆ˜์˜ ํŠน์ง•

1) ๋™์ž‘์ด ๋งค์šฐ ๋น ๋ฅด๋‹ค.(ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ž‘์ด ๋นจ๋ผ์•ผํ•œ๋‹ค.)

2) ๊ธฐ๋ณธ์ ์œผ๋กœ ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ๋ถ„๋ฐฐ ํ•ด์„œ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋“ค๊ณผ ๊ฒน์น˜์ง€ ์•Š๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค.(๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ธฐ์ค€ ์„ค์ •์ด ๋งค์šฐ ์–ด๋ ต๋‹ค.)

3) ๊ฒฐ์ •๋ก ์ ์ด๋‹ค.(ํŠน์ • ์ž…๋ ฅ๊ฐ’์„ ์ž…๋ ฅํ•  ๋•Œ๋งˆ๋‹ค ๋ฌด์กฐ๊ฑด ๊ฐ™์€ ์ถœ๋ ฅ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•œ๋‹ค.)

 

19.3 ํ•ด์‹œ ํ•จ์ˆ˜

//์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ๋งŒ๋“ค๋“  ์ƒ๊ด€ ์—†์ง€๋งŒ, ์ค‘์š”ํ•œ๊ฒƒ์€ ๋น ๋ฅด๊ณ , ํ•ญ์ƒ ๋™์ผํ•œ ์ž…๋ ฅ์— ๋™์ผํ•œ ์ถœ๋ ฅ์ด ๋‚˜์™€์•ผํ•œ๋‹ค๋Š” ์ ์ด๋‹ค!
function hash(key, arrayLen) { // arrayLen์€ ๋ฐฐ์—ด์˜ ๊ธธ์ด๋ฅผ ์˜๋ฏธํ•จ! 
    //๋ช‡๊ฐœ์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ง€๋Š” ๋ฐฐ์—ด์—์„œ ์–ด๋””์— ์ €์žฅํ• ์ง€๋ฅผ ์ฐพ๊ธฐ์œ„ํ•ด ๋ฐฐ์—ด์˜ ๊ธธ์ด๋„ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๊ฒƒ์ž„!
  let total = 0;
  for (let char of key) {
    let value = char.charCodeAt(0) - 96 // 96์„ ๋นผ๋ฉด ์•ŒํŒŒ๋ฒณ ์ˆœ์„œ๊ฐ€ ๋‚˜์˜จ๋‹ค!! 
    //charCodeAt() ๋ฉ”์„œ๋“œ๋Š” ์ฃผ์–ด์ง„ ์ธ๋ฑ์Šค์— ๋Œ€ํ•œ UTF-16 ์ฝ”๋“œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” 0๋ถ€ํ„ฐ 65535 ์‚ฌ์ด์˜ ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
    total = (total + value) % arrayLen;
  }
  return total;
}

โ€ป ์œ„ ํ•ด์‰ฌ ํ•จ์ˆ˜์˜ ๋ฌธ์ œ์ 

1) ๋ฌธ์ž์—ด์— ๋Œ€ํ•ด์„œ๋งŒ ํ•ด์‹œ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. ์ˆซ์ž๋‚˜ ๋ถˆ๋ฆฌ์–ธ ๊ฐ’์ด๋‚˜ ๋ฐฐ์—ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

2) O(N)์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ–๋Š”๋‹ค. ์ฆ‰, ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๊ฐ€ ๊ธธ์–ด์ง€๋ฉด ๊ณ„์‚ฐํ•˜๋Š” ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง„๋‹ค.

3) ๋ฌด์ž‘์œ„์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.(ํ•ด์‹œ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์ด ๋™์ผํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.)

์ด๋Ÿฌํ•œ ๋ฌธ์ œ์ ๋“ค์„ ๊ฐœ์„ ํ•ด์„œ ๋‹ค์‹œ ์œ„์˜ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž.

// ์œ„ ๋ฌธ์ œ์ ๋“ค์„ ํ† ๋Œ€๋กœ ์„ฑ๋Šฅ ํ–ฅ์ƒ์‹œ์ผœ๋ณด๊ธฐ
function hash(key, arrayLen) {
  let total = 0;
  let WEIRD_PRIME = 31; // ์†Œ์ˆ˜๋ฅผ ํ•˜๋‚˜ ์‚ฌ์šฉํ•œ๋‹ค!(์–ด๋–ค ์ˆซ์ž๋กœ๋„ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ์ˆ˜)
  //ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ๊ฑฐ์˜ ๋Œ€๋ถ€๋ถ„ ์†Œ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•จ
  //์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ถฉ๋Œ์ด ์ค„์–ด๋“ ๋‹ค. ๋ฐ์ดํ„ฐ๋“ค์ด ์ตœ๋Œ€ํ•œ ๊ฐ™์€ ๋ฐ”๊ตฌ๋‹ˆ์— ๋“ค์–ด๊ฐ€์ง€ ์•Š๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด
  //์ˆ˜ํ•™์  ์›๋ฆฌ๋Š” ์ œ์ณ์ฃผ๋„ ํ•ด์‰ฌ ํ•จ์ˆ˜์— ๋ณดํ†ต ์†Œ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š”๊ฒƒ์„ ๊ธฐ์–ต!
  //์‹ฌ์ง€์–ด ๋ฐฐ์—ด๋„ ์†Œ์ˆ˜๋ผ๋ฉด ์ถฉ๋Œ ๊ฐ€๋Šฅ์„ฑ๋„ ์—„์ฒญ๋‚˜๊ฒŒ ๋–จ์–ด์ง!(์†Œ์ˆ˜ ๊ฐ’์˜ ํ…Œ์ด๋ธ”๊ณผ ์ง์ˆ˜ ๊ฐ’์˜ ํ…Œ์ด๋ธ” ์ถฉ๋Œ ํšŸ์ˆ˜์ฐจ์ด๊ฐ€ ์ˆ˜์‹ญ๋ฐฐ์—์„œ ์ˆ˜์ฒœ๋ฐฐ๊นŒ์ง€๋„ ๋‚จ!)
  for (let i = 0; i < Math.min(key.length, 100); i++) { 
    // ์ฆ‰ ๋ฐ˜๋ณต์€ 100์ดํ•˜๋กœ๋งŒ ํ•˜๊ฒŒ ๋จ!(์•„๋ฌด๋ฆฌ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ธธ์–ด๋„ 100๋ฒˆ๊นŒ์ง€๋งŒ ๋Œ๊ฒŒ๋จ 0~99) ์†๋„๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด
    let char = key[i];
    let value = char.charCodeAt(0) - 96
    total = (total * WEIRD_PRIME + value) % arrayLen;
  }
  return total;
}

19.4 ํ•ด์‹œ ํ•จ์ˆ˜ ์ถฉ๋Œ ์ฒ˜๋ฆฌ

  ์ž„์˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด์‹œ ์ฒ˜๋ฆฌ ํ–ˆ๋Š”๋ฐ ๊ฐ™์€ ๊ฐ’์ด ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒฝ์šฐ์˜ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์—๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ 2๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ๊ฐœ๋ณ„ ์ฒด์ด๋‹(Separate Chaining) ๋ฐฉ๋ฒ•๊ณผ ์ง์„  ํƒ์ƒ‰๋ฒ•(Linear Probing)์ด ์žˆ๋‹ค.

 

1) ๊ฐœ๋ณ„ ์ฒด์ด๋‹(Separate Chaining)

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

( [ [  ],[  ] ] )์ฆ‰, ๊ฐ™์€ ๊ณต๊ฐ„์— ๊ฐ™์ด ์ €์žฅํ•˜๋Š”๊ฒƒ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์˜ ์žฅ์ ์€ ๋ฐฐ์—ด์˜ ๊ธธ์ด ๋ณด๋‹ค ๋” ๊ธด ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2) ์ง์„  ํƒ์ƒ‰๋ฒ•(Linear Probing)

  ๊ฐ ์œ„์น˜์— ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋งŒ ์ €์žฅํ•œ๋‹ค๋Š” ๊ทœ์น™์„ ๊ทธ๋Œ€๋กœ ์ง€ํ‚ค๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ์œ„์น˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ ๋น„์–ด์žˆ๋Š” ๊ณต๊ฐ„์ด ์–ด๋””์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์ €์žฅํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ™์€ ์ธ๋ฑ์Šค์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฑ ๋ฐฐ์—ด์˜ ๊ธธ์ด์— ๋งž๋Š” ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜๋งŒ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

19.5 ํ•ด์‹œ ํ…Œ์ด๋ธ”๊ณผ set & get ๋ฉ”์„œ๋“œ

  set๋ฉ”์„œ๋“œ๋Š” ์ž„์˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด์‹œ ์ฒ˜๋ฆฌ ํ›„ ํ•ด์‹œ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๊ณ , get ๋ฉ”์„œ๋“œ๋Š” ์ด๋ฏธ ํ•ด์‹œ ํ…Œ์ด๋ธ”์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ํ‚ค๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค. 

class HashTable {
  constructor(size=53){
    this.keyMap = new Array(size);
  }

  _hash(key) { //ํ‚ค๋ฅผ ๋ฐ›์•„ ํ•ด์‹œ ํ•จ์ˆ˜๋กœ ์ €์žฅ์œ„์น˜์ธ ํ•ด์‹œํ…Œ์ด๋ธ”์˜ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ ๋ฐ›๊ธฐ
    let total = 0;
    let WEIRD_PRIME = 31;
    for (let i = 0; i < Math.min(key.length, 100); i++) {
      let char = key[i];
      let value = char.charCodeAt(0) - 96
      total = (total * WEIRD_PRIME + value) % this.keyMap.length;
    }
    return total;
  }
  
  set(key,value){ //ํ‚ค์™€ ๊ฐ’์„ ๋ฐ›์•„ ํ•ด์‹œํ…Œ์ด๋ธ”์— ์ €์žฅ
    let index = this._hash(key);
    if(!this.keyMap[index]){ // ๋ฐฐ์—ด์•ˆ์— ํ•ด๋‹น ์ธ๋ฑ์Šค๊ฐ€ ์—†์œผ๋ฉด undefined๊ฐ€ ๋ฐ˜ํ™˜๋จ
        //์ฐธ๊ณ ๋กœ ๋นˆ ๋ฐฐ์—ด ์ž์ฒด๋Š” truthy์ž„!!! 
      this.keyMap[index] = [];
    }
    this.keyMap[index].push([key, value]); //ํ•ด๋‹น ์ธ๋ฑ์Šค๋กœ ์ ‘๊ทผํ•˜๋ฉด ๋˜ ๋‹ค๋ฅธ ๋ฐฐ์—ด์ด ๋‚˜์˜ค 
    //๊ทธ ๋ฐฐ์—ด์— push๋ฉ”์„œ๋“œ ํ™œ์šฉ
  }
  
  get(key){ //ํ‚ค๋ฅผ ๋ฐ›์•„ ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ์ฐพ๊ธฐ
    let index = this._hash(key);
    if(this.keyMap[index]){
      for(let i = 0; i < this.keyMap[index].length; i++){
        if(this.keyMap[index][i][0] === key) {
          return this.keyMap[index][i][1] //๋ฐฐ์—ด ์•ˆ์— ๋ฐฐ์—ด ์•ˆ์— ๋ฐฐ์—ด ์•ˆ์˜ 1๋ฒˆ ์ธ๋ฑ์Šค์ž„
        }
      }
    }
    return undefined;
  }
}

 

'๐Ÿ“š Language & CS knowledge > Algorithm & Data structure' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

21 ๊ทธ๋ž˜ํ”„ ์ˆœํšŒ  (0) 2022.08.19
20 ๊ทธ๋ž˜ํ”„  (0) 2022.08.17
18 ์ด์ง„ ํž™  (0) 2022.08.16
17 ํŠธ๋ฆฌ ์ˆœํšŒ  (0) 2022.08.16
16 ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ  (0) 2022.08.14