Skip to content

Latest commit

ย 

History

History
3817 lines (2934 loc) ยท 133 KB

algorithm_data_structure.md

File metadata and controls

3817 lines (2934 loc) ยท 133 KB

๋ชฉ์ฐจ

Frequency Counters

Frequency Counters๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ํŠน์ • ์š”์†Œ์˜ ๋ฐœ์ƒ ๋นˆ๋„๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ๋ฐฐ์—ด, ๋ฌธ์ž์—ด ๋˜๋Š” ๋‹ค๋ฅธ ์ž๋ฃŒ ๊ตฌ์กฐ ๋‚ด์—์„œ ์š”์†Œ์˜ ๋นˆ๋„๋ฅผ ์„ธ์–ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ์ค„์ด๊ณ  ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

Frequency Counter์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ž๋ฃŒ ๊ตฌ์กฐ ์„ ํƒ: ์ฃผ๋กœ ํ•ด์‹œ๋งต(๋˜๋Š” ๊ฐ์ฒด)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์š”์†Œ์˜ ๋ฐœ์ƒ ๋นˆ๋„๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐ˜๋ณต๋ฌธ ์‚ฌ์šฉ: ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ ์š”์†Œ์˜ ๋นˆ๋„๋ฅผ ํ•ด์‹œ๋งต์— ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฒฐ๊ณผ ๋ถ„์„: ํ•„์š”์— ๋”ฐ๋ผ ๋นˆ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ตฌํ˜„์€ ๊ฐ ๋ฐฐ์—ด ๋˜๋Š” ๋ฌธ์ž์—ด์„ ํ•œ ๋ฒˆ๋งŒ ์ˆœํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(n)์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํšจ์œจ์ ์ธ ํ•ด๊ฒฐ์ฑ…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ™œ์šฉ ์˜ˆ์‹œ

Frequency Counter ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์— ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์• ๋„ˆ๊ทธ๋žจ(Anagram) ๋ฌธ์ œ ํ•ด๊ฒฐ
  • ๋ฐฐ์—ด ๋‚ด ์ค‘๋ณต ์š”์†Œ ์ฐพ๊ธฐ
  • ๋ฐ์ดํ„ฐ ์ง‘ํ•ฉ์—์„œ ๊ฐ€์žฅ ๋งŽ์ด/์ ๊ฒŒ ๋ฐœ์ƒํ•œ ์š”์†Œ ์ฐพ๊ธฐ
  • ์ฃผ์–ด์ง„ ์กฐ๊ฑด์— ๋งž๋Š” ๋ถ€๋ถ„ ๋ฐฐ์—ด ์ฐพ๊ธฐ
function charCount(str) {
  // ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ
  // ๋ฌธ์ž๋ฅผ ํ•˜๋‚˜์”ฉ ๋–ผ์„œ ๋ฐฐ์—ด ์•ˆ์— ๋„ฃ๊ธฐ
  let arr = [];
  let result = {};

  arr = str.toLowerCase().split('');

  // ๋ฐฐ์—ด์„ ์ˆœํšŒํ•˜๋ฉด์„œ ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜๋ฅผ ์„ธ๊ธฐ
  for (let i = 0; i < arr.length; i++) {
    // 0-9, a-z ์‚ฌ์ด์˜ ๋ฌธ์ž์ธ์ง€ ์ •๊ทœ ํ‘œํ˜„์‹์„ ํ†ตํ•ด ํ™•์ธํ•˜๊ธฐ

    if (!/[0-9a-z]/.test(arr[i])) continue;

    if (result[arr[i]] > 0) {
      result[arr[i]]++;
    } else {
      result[arr[i]] = 1;
    }
  }

  return result;
}

console.log(charCount('Hello')); // { h: 1, e: 1, l: 2, o: 1 }
console.log(charCount('Your Pin is 1234 !'));

/*
{
  '1': 1,
  '2': 1,
  '3': 1,
  '4': 1,
  y: 1,
  o: 1,
  u: 1,
  r: 1,
  p: 1,
  i: 2,
  n: 1,
  s: 1
}
*/

/**
 * ์‚ฌ์šฉํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
 *
 * - String.prototype.toLowerCase: ๋ฌธ์ž์—ด์„ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
 * - String.prototype.split: ๋ฌธ์ž์—ด์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.
 * - RegExp.prototype.test: ๋ฌธ์ž์—ด์ด ์ •๊ทœ ํ‘œํ˜„์‹๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
 * - if ๋ฌธ, continue: ๋ฐ˜๋ณต๋ฌธ์„ ์ค‘๋‹จํ•˜๊ณ  ๋‹ค์Œ ๋ฐ˜๋ณต์œผ๋กœ ๋„˜์–ด๊ฐ„๋‹ค.
 */

๋ฐฐ์—ด๋กœ ๋น„๊ต

  • for ๋ฌธ ๋‚ด๋ถ€์—์„œ indexOf๋กœ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— O(n^2)
function same(arr1, arr2) {
  if (arr1.length !== arr2.length) return false;

  for (let i = 0; i < arr1.length; i++) {
    let correctIndex = arr2.indexOf(arr1[i] ** 2);
    if (correctIndex === -1) return false;

    // console.log(arr2);
    arr2.splice(correctIndex, 1);
  }
  return true;
}

console.log(same([1, 2, 3], [4, 1, 9])); // true
console.log(same([1, 2, 3], [1, 9])); // false
console.log(same([1, 2, 1], [4, 4, 1])); // false

/**
 * ์‚ฌ์šฉํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
 * - Array.prototype.indexOf: ๋ฐฐ์—ด์—์„œ ํŠน์ • ์š”์†Œ๋ฅผ ์ฐพ์•„ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์—†์œผ๋ฉด -1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
 * - Array.prototype.splice: ๋ฐฐ์—ด์—์„œ ํŠน์ • ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
 */

๊ฐ์ฒด๋กœ ๋น„๊ต

  • for ๋ฌธ ๋‚ด๋ถ€๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ์ฒด ๋‚ด๋ถ€๋ฅผ index๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ access ํ•˜๊ธฐ ๋•Œ๋ฌธ์— O(n)
function same2(arr1, arr2) {
  if (arr1.length !== arr2.length) return false;

  let frequencyCounter1 = {};
  let frequencyCounter2 = {};

  for (let val of arr1) {
    frequencyCounter1[val] = (frequencyCounter1[val] || 0) + 1;
  }

  for (let val of arr2) {
    frequencyCounter2[val] = (frequencyCounter2[val] || 0) + 1;
  }

  console.log(frequencyCounter1);
  console.log(frequencyCounter2);

  for (let key in frequencyCounter1) {
    // { key: value } ์ค‘ key ์ฒดํฌ
    if (!(key ** 2 in frequencyCounter2)) return false;

    // { key: value } ์ค‘ value ์ฒดํฌ
    if (frequencyCounter2[key ** 2] !== frequencyCounter1[key]) return false;
  }

  return true;
}

console.log(same2([1, 2, 3], [4, 1, 9])); // true
console.log(same2([1, 2, 3, 3], [4, 9, 1, 9])); // true
console.log(same2([1, 2, 3], [1, 9])); // false

/*
{ '1': 1, '2': 1, '3': 1 }
{ '1': 1, '4': 1, '9': 1 }
true

{ '1': 1, '2': 1, '3': 2 }
{ '1': 1, '4': 1, '9': 2 }
true

false
*/

/**
 * ์‚ฌ์šฉํ•œ ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
 * - for...of ๋ฌธ: ๋ฐฐ์—ด์˜ ์š”์†Œ๋ฅผ ์ˆœํšŒํ•œ๋‹ค.
 * - for...in ๋ฌธ: ๊ฐ์ฒด์˜ ํ‚ค๋ฅผ ์ˆœํšŒํ•œ๋‹ค.
 */

Anagram

// time complexity: O(n)

function validAnagram(str1, str2) {
  let strCounter1 = {};
  let strCounter2 = {};

  for (let char of str1) {
    strCounter1[char] = (strCounter1[char] || 0) + 1;
  }

  for (let char of str2) {
    strCounter2[char] = (strCounter2[char] || 0) + 1;
  }

  for (let key in strCounter1) {
    if (!(key in strCounter2)) return false;

    if (strCounter2[key] !== strCounter1[key]) return false;
  }

  return true;
}

console.log(validAnagram('', ''));
console.log(validAnagram('aaz', 'zza'));
console.log(validAnagram('anagram', 'nagaram'));
console.log(validAnagram('rat', 'car'));
console.log(validAnagram('awesome', 'awesom'));
console.log(validAnagram('amanaplanacanalpanama', 'acanalmanplanpamana'));
console.log(validAnagram('qwerty', 'qeywrt'));
console.log(validAnagram('texttwisttime', 'timetwisttext'));

/**
 * validAnagram('', '') // true
 * validAnagram('aaz', 'zza') // false
 * validAnagram('anagram', 'nagaram') // true
 * validAnagram("rat","car") // false) // false
 * validAnagram('awesome', 'awesom') // false
 * validAnagram('amanaplanacanalpanama', 'acanalmanplanpamana') // false
 * validAnagram('qwerty', 'qeywrt') // true
 * validAnagram('texttwisttime', 'timetwisttext') // true
 */

Multipleย Pointers

Multiple Pointers์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ํฌ์ธํ„ฐ ์„ค์ •: ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด์˜ ์‹œ์ž‘๊ณผ ๋, ๋˜๋Š” ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ํฌ์ธํ„ฐ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ํฌ์ธํ„ฐ ์ด๋™: ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•  ๋•Œ๊นŒ์ง€ ํฌ์ธํ„ฐ๋ฅผ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  3. ์กฐ๊ฑด ๋งŒ์กฑ ํ™•์ธ: ํฌ์ธํ„ฐ๊ฐ€ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

Multiple Pointers๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ O(n)์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด์„ ํ•œ ๋ฒˆ๋งŒ ์ˆœํšŒํ•˜๋ฉด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ™œ์šฉ ์˜ˆ์‹œ

Multiple Pointers ๊ธฐ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • ๋‘ ๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ๋‚ด ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ ์ฐพ๊ธฐ
  • ์ค‘๋ณต ์š”์†Œ ์ œ๊ฑฐ
  • ๋ฌธ์ž์—ด ๋‚ด ํŠน์ • ํŒจํ„ด ์ฐพ๊ธฐ
  • ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํŠน์ • ํ•ฉ์„ ๊ฐ€์ง€๋Š” ์Œ ์ฐพ๊ธฐ

์ด์ค‘ for๋ฌธ ์‚ฌ์šฉ

// time complexity o(n^2)

function sumZero(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] + arr[j] === 0) {
        return [arr[i], arr[j]];
      }
    }
  }
  return undefined;
}

console.log(sumZero([-5, -2, -1, 0, 1, 2, 3]));
console.log(sumZero([-3, -2, -1, 0, 1, 2, 3]));
console.log(sumZero([-2, 0, 1, 3]));
console.log(sumZero([1, 2, 3]));

// sumZero([-3,-2,-1,0,1,2,3]) >> [-3,3]
// sumZero([-2,0,1,3]) >> undefined
// sumZero([1,2,3]) >> undefined

While ๋ฌธ ์‚ฌ์šฉ, ๋‹จ์ผ for๋ฌธ ์‚ฌ์šฉ โœ”

// time complexity o(n)

function sumZero(arr) {
  let left = 0;
  let right = arr.length - 1;

  while (left < right) {
    let sum = arr[left] + arr[right];
    if (sum === 0) {
      return [arr[left], arr[right]];
    } else if (sum > 0) {
      right--;
    } else {
      left++;
    }
  }
  return undefined;
}

console.log(sumZero([-5, -2, -1, 0, 1, 2, 3]));
console.log(sumZero([-3, -2, -1, 0, 1, 2, 3]));
console.log(sumZero([-2, 0, 1, 3]));
console.log(sumZero([1, 2, 3]));

// sumZero([-3,-2,-1,0,1,2,3]) >> [-3,3]
// sumZero([-2,0,1,3]) >> undefined
// sumZero([1,2,3]) >> undefined

๋‘ ๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ๋‚ด ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์š”์†Œ ์ฐพ๊ธฐ

// ์ •๋ ฌ๋œ ๋ฐฐ์—ด์„ ๋ฐ›์•„๋“ค์ด๊ณ  ๋ฐฐ์—ด์˜ ๊ณ ์œ  ๊ฐ’์„ ์„ธ๋Š” countUniqueValues๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์— ์Œ์ˆ˜๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํ•ญ์ƒ ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.

function countUniqueValues(arr) {
  let left = 0;
  let right = 1;

  if (arr.length === 0) return 0; // ๋นˆ ๋ฐฐ์—ด์ธ ๊ฒฝ์šฐ 0 ๋ฐ˜ํ™˜

  while (right < arr.length) {
    if (arr[left] !== arr[right]) {
      left++;
      arr[left] = arr[right]; // ์ค‘๋ณต๋˜์ง€ ์•Š๋Š” ๊ฐ’์„ ์™ผ์ชฝ์œผ๋กœ ์˜ฎ๊น€
    }
    right++;
  }

  return left + 1; // left ์ธ๋ฑ์Šค๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ 1์„ ๋”ํ•ด ์œ ์ผํ•œ ๊ฐ’์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜
}

console.log(countUniqueValues([1, 1, 1, 1, 1, 2])); // 2
console.log(countUniqueValues([1, 2, 3, 4, 4, 4, 7, 7, 12, 12, 13])); // 7
console.log(countUniqueValues([])); // 0
console.log(countUniqueValues([-2, -1, -1, 0, 1])); // 4
 // ๊ธฐ๋ณธ ์„ธํŒ… >> left = 0, right = 1

 i
[1, 2, 3, 4, 4, 4, 7, 7, 12, 12, 13]
    j

Sliding Window

Sliding Window๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์€ ์—ฐ์†๋œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋‚ด์—์„œ ๋ถ€๋ถ„ ์ง‘ํ•ฉ์˜ ํ•ฉ, ํ‰๊ท , ์ตœ๋Œ€๊ฐ’ ๋˜๋Š” ์ตœ์†Œ๊ฐ’ ๋“ฑ์„ ํšจ์œจ์ ์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ ๊ณ ์ •๋œ ํฌ๊ธฐ๋‚˜ ๊ฐ€๋ณ€ ํฌ๊ธฐ์˜ ์œˆ๋„์šฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

Sliding Window์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์œˆ๋„์šฐ ์„ค์ •: ์ดˆ๊ธฐ ์œˆ๋„์šฐ ํฌ๊ธฐ๋‚˜ ์‹œ์ž‘์ ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ์œˆ๋„์šฐ ์ด๋™: ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์ด๋™ํ•˜๋ฉด์„œ ์œˆ๋„์šฐ ๋‚ด ๊ฐ’์„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฒฐ๊ณผ ๊ฐฑ์‹ : ์œˆ๋„์šฐ ๋‚ด ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ํ•„์š”ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

์˜ˆ์ œ 1: ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ์œˆ๋„์šฐ๋ฅผ ์‚ฌ์šฉํ•œ ์ตœ๋Œ€ ํ•ฉ ์ฐพ๊ธฐ

๋‹ค์Œ์€ ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ์œˆ๋„์šฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ๋‚ด ์—ฐ์†๋œ ์š”์†Œ๋“ค์˜ ์ตœ๋Œ€ ํ•ฉ์„ ์ฐพ๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function maxSubarraySum(arr, num) {
  if (arr.length < num) return null;

  let maxSum = 0;
  let tempSum = 0;

  for (let i = 0; i < num; i++) {
    maxSum += arr[i];
  }
  tempSum = maxSum;

  for (let i = num; i < arr.length; i++) {
    tempSum = tempSum - arr[i - num] + arr[i];
    maxSum = Math.max(maxSum, tempSum);
  }

  return maxSum;
}

console.log(maxSubarraySum([1, 2, 5, 2, 8, 1, 5], 2)); // 10

์‹œ๊ฐ„ ๋ณต์žก๋„

Sliding Window๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ O(n)์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ˆœํšŒํ•˜๋ฉด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ™œ์šฉ ์˜ˆ์‹œ

Sliding Window ๊ธฐ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ์œˆ๋„์šฐ ๋‚ด ์ตœ๋Œ€/์ตœ์†Œ ํ•ฉ ๋˜๋Š” ํ‰๊ท  ๊ณ„์‚ฐ
  • ๊ฐ€๋ณ€ ํฌ๊ธฐ์˜ ์œˆ๋„์šฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ์ตœ์†Œ/์ตœ๋Œ€ ๊ธธ์ด ๋ถ€๋ถ„ ๋ฐฐ์—ด ์ฐพ๊ธฐ
  • ๋ฌธ์ž์—ด ๋‚ด ํŠน์ • ํŒจํ„ด ์ฐพ๊ธฐ
  • ๋ฐฐ์—ด ๋‚ด ์—ฐ์†๋œ ๋ถ€๋ถ„ ๋ฐฐ์—ด์˜ ํ•ฉ ๋˜๋Š” ๊ณฑ ๊ณ„์‚ฐ

์ด ๊ธฐ๋ฒ•์€ ํŠนํžˆ ๋ฐฐ์—ด์ด๋‚˜ ๋ฌธ์ž์—ด๊ณผ ๊ฐ™์€ ์—ฐ์†๋œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ ํšจ์œจ์ ์œผ๋กœ ๋ถ€๋ถ„ ์ง‘ํ•ฉ์„ ๋ถ„์„ํ•˜๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Divide and Conquer

Divide and Conquer์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๋ถ„ํ• (Divide): ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๋ฌธ์ œ๋ฅผ ๋™์ผํ•œ ์œ ํ˜•์˜ ๋” ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.
  2. ์ •๋ณต(Conquer): ๊ฐ ๋ถ€๋ถ„ ๋ฌธ์ œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ž‘์œผ๋ฉด ์ง์ ‘ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฒฐํ•ฉ(Combine): ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ํ•ฉ์ณ์„œ ์›๋ž˜ ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.

์˜ˆ์ œ

์˜ˆ์ œ 1: ๋ณ‘ํ•ฉ ์ •๋ ฌ (Merge Sort)

๋ณ‘ํ•ฉ ์ •๋ ฌ์€ Divide and Conquer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆˆ ํ›„ ๊ฐ๊ฐ์„ ์ •๋ ฌํ•˜๊ณ , ์ •๋ ฌ๋œ ๋ถ€๋ถ„ ๋ฐฐ์—ด์„ ํ•ฉ์นฉ๋‹ˆ๋‹ค.

function merge(arr1, arr2) {
  let idx1 = 0;
  let idx2 = 0;
  let result = [];

  while (idx1 < arr1.length && idx2 < arr2.length) {
    if (arr1[idx1] < arr2[idx2]) {
      result.push(arr1[idx1]);
      idx1++;
    } else {
      result.push(arr2[idx2]);
      idx2++;
    }
  }

  // Remaining elements from arr1
  while (idx1 < arr1.length) {
    result.push(arr1[idx1]);
    idx1++;
  }

  // Remaining elements from arr2
  while (idx2 < arr2.length) {
    result.push(arr2[idx2]);
    idx2++;
  }

  return result;
}

function mergeSort(arr) {
  if (arr.length <= 1) return arr;

  let mid = Math.floor(arr.length / 2);
  let left = mergeSort(arr.slice(0, mid));
  let right = mergeSort(arr.slice(mid));

  return merge(left, right);
}

console.log(mergeSort([8, 3, 5, 4, 7, 6, 1, 2]));

์˜ˆ์ œ 2: ์ด์ง„ ํƒ์ƒ‰ (Binary Search)

์ด์ง„ ํƒ์ƒ‰์€ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์—์„œ ํŠน์ • ๊ฐ’์„ ์ฐพ๋Š” ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฐ’์ด ์–ด๋Š ์ชฝ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ํ›„, ํ•ด๋‹น ์ ˆ๋ฐ˜์—์„œ ๋‹ค์‹œ ํƒ์ƒ‰์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

function binarySearch(arr, target) {
  var start = 0;
  var end = arr.length - 1;
  var middle = Math.floor((start + end) / 2);

  while (arr[middle] !== target && start <= end) {
    if (target < arr[middle]) {
      end = middle - 1;
    } else {
      start = middle + 1;
    }
    middle = Math.floor((start + end) / 2);
  }
  if (arr[middle] === target) {
    return middle;
  }
  return -1;
}

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(binarySearch(arr, 7)); // 6
console.log(binarySearch(arr, 11)); // -1

์‹œ๊ฐ„ ๋ณต์žก๋„

Divide and Conquer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋ฌธ์ œ์˜ ์ข…๋ฅ˜์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

  • ๋ณ‘ํ•ฉ ์ •๋ ฌ: O(n log n)
  • ์ด์ง„ ํƒ์ƒ‰: O(log n)

ํ™œ์šฉ ์˜ˆ์‹œ

Divide and Conquer ๊ธฐ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์˜ˆ: ๋ณ‘ํ•ฉ ์ •๋ ฌ, ํ€ต ์ •๋ ฌ)
  • ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์˜ˆ: ์ด์ง„ ํƒ์ƒ‰)
  • ํ–‰๋ ฌ ๊ณฑ์…ˆ (Strassen ์•Œ๊ณ ๋ฆฌ์ฆ˜)
  • ํฐ ์ˆ˜์˜ ๊ณฑ์…ˆ (Karatsuba ์•Œ๊ณ ๋ฆฌ์ฆ˜)
  • ์ตœ๊ทผ์ ‘ ์  ๋ฌธ์ œ

์ด ๊ธฐ๋ฒ•์€ ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ๋” ์ž‘์€ ๋ฌธ์ œ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ํ•ด๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ํšจ์œจ์ ์ด๋ฉฐ, ๋งŽ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ํ•ต์‹ฌ์ ์ธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Recursion

์žฌ๊ท€(Recursion)๋Š” ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์žฌ๊ท€๋Š” ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด ํ•ด๊ฒฐํ•  ๋•Œ ํŠนํžˆ ์œ ์šฉํ•˜๋ฉฐ, Divide and Conquer์™€ ๊ฐ™์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ธฐ๋ฒ•๊ณผ ์ž์ฃผ ๊ฒฐํ•ฉ๋ฉ๋‹ˆ๋‹ค. ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ์กฐ๊ฑด(base case)๊ณผ ์žฌ๊ท€ ์กฐ๊ฑด(recursive case)์„ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

  1. ๊ธฐ๋ณธ ์กฐ๊ฑด (Base Case): ์žฌ๊ท€ ํ˜ธ์ถœ์„ ๋ฉˆ์ถ”๋Š” ์กฐ๊ฑด์ž…๋‹ˆ๋‹ค. ๋” ์ด์ƒ ๋ฌธ์ œ๋ฅผ ์ชผ๊ฐค ์ˆ˜ ์—†์„ ๋•Œ ๊ธฐ๋ณธ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. ์žฌ๊ท€ ์กฐ๊ฑด (Recursive Case): ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ๋” ์ž‘์€ ๋ถ€๋ถ„์œผ๋กœ ์ชผ๊ฐœ๊ณ , ๊ทธ ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์‹œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

์˜ˆ์ œ 1: ํŒฉํ† ๋ฆฌ์–ผ ๊ณ„์‚ฐ

ํŒฉํ† ๋ฆฌ์–ผ์€ 1๋ถ€ํ„ฐ n๊นŒ์ง€์˜ ์ •์ˆ˜๋ฅผ ๋ชจ๋‘ ๊ณฑํ•œ ๊ฐ’์ž…๋‹ˆ๋‹ค. ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒฉํ† ๋ฆฌ์–ผ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function factorial(n) {
  if (n === 0) return 1; // ๊ธฐ๋ณธ ์กฐ๊ฑด
  return n * factorial(n - 1); // ์žฌ๊ท€ ์กฐ๊ฑด
}

console.log(factorial(5)); // 120

์˜ˆ์ œ 2: ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์˜ ๊ฐ ํ•ญ์€ ์•ž์˜ ๋‘ ํ•ญ์˜ ํ•ฉ์ž…๋‹ˆ๋‹ค. ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function fibonacci(n) {
  if (n <= 1) return n; // ๊ธฐ๋ณธ ์กฐ๊ฑด
  return fibonacci(n - 1) + fibonacci(n - 2); // ์žฌ๊ท€ ์กฐ๊ฑด
}

console.log(fibonacci(7)); // 13

์˜ˆ์ œ 3: ๋ฐฐ์—ด์˜ ํ•ฉ ๊ณ„์‚ฐ

์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์˜ ํ•ฉ์„ ๊ณ„์‚ฐํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function sumArray(arr) {
  if (arr.length === 0) return 0; // ๊ธฐ๋ณธ ์กฐ๊ฑด
  return arr[0] + sumArray(arr.slice(1)); // ์žฌ๊ท€ ์กฐ๊ฑด
}

let arr = [1, 2, 3, 4, 5];
console.log(sumArray(arr)); // 15

์˜ˆ์ œ 4: ์ œ๊ณฑ๊ทผ ๋งŒ๋“ค๊ธฐ, helper ํ•จ์ˆ˜ ์‚ฌ์šฉ

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Math.prototype.pow()๋ฅผ ๋ณธ๋”ฐ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค
  • helper ํ•จ์ˆ˜๋Š” ์žฌ๊ท€์ ์ด์ง€ ์•Š์€ ์™ธ๋ถ€ ํ•จ์ˆ˜๊ฐ€ ์žฌ๊ท€์ ์ธ ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.
function power(number, cnt) {
  let result = 1;
  if (cnt === 0) return 1;

  function helper(number, cnt) {
    if (cnt === 0) return;

    result *= number;
    cnt--;

    helper(number, cnt);
  }
  helper(number, cnt);

  return result;
}

power(2, 0); // 1
power(2, 2); // 4
power(2, 4); // 16

์˜ˆ์ œ 5: ์ˆซ์ž ๋ฐฐ์—ด์„ ๋ฐ›์•„ ๋ชจ๋“  ์ˆซ์ž์˜ ๊ณฑ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ, helper ํ•จ์ˆ˜ ์‚ฌ์šฉ

function productOfArray(arr) {
  let result = 1;
  if (arr.length === 0) return null;

  function helper(arr) {
    if (arr.length === 0) return;

    result *= arr[0];

    helper(arr.slice(1));
  }

  helper(arr);

  return result;
}

productOfArray([1, 2, 3]); // 6
productOfArray([1, 2, 3, 10]); // 60

์‹œ๊ฐ„ ๋ณต์žก๋„

์žฌ๊ท€ ํ•จ์ˆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ ํšŸ์ˆ˜์™€ ๊ฐ ํ˜ธ์ถœ๋‹น ์ž‘์—…์˜ ์–‘์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์˜ ์žฌ๊ท€ ๊ตฌํ˜„์€ ์ค‘๋ณต ๊ณ„์‚ฐ์ด ๋งŽ์•„ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(2^n)์œผ๋กœ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, ๋ฉ”๋ชจ์ด์ œ์ด์…˜(memoization)์„ ์‚ฌ์šฉํ•˜๋ฉด ํšจ์œจ์ ์œผ๋กœ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์ 

  1. ๊ธฐ๋ณธ ์กฐ๊ฑด์˜ ์ค‘์š”์„ฑ: ๊ธฐ๋ณธ ์กฐ๊ฑด์ด ์—†์œผ๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋ฌดํ•œํžˆ ํ˜ธ์ถœ๋˜์–ด ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ(stack overflow)๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  2. ์žฌ๊ท€ ๊นŠ์ด ์ œํ•œ: ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋Š” ์žฌ๊ท€ ํ˜ธ์ถœ์˜ ์ตœ๋Œ€ ๊นŠ์ด๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ๊นŠ์ด๊ฐ€ ๋„ˆ๋ฌด ๊นŠ์œผ๋ฉด ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋ฉ”๋ชจ์ด์ œ์ด์…˜: ์ค‘๋ณต ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™œ์šฉ ์˜ˆ์‹œ

์žฌ๊ท€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค:

  • ํŠธ๋ฆฌ ๋ฐ ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰ (์˜ˆ: DFS)
  • ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์˜ˆ: ํ€ต ์ •๋ ฌ, ๋ณ‘ํ•ฉ ์ •๋ ฌ)
  • ์กฐํ•ฉ๋ก  ๋ฌธ์ œ (์˜ˆ: ์ˆœ์—ด, ์กฐํ•ฉ)
  • ๋™์  ๊ณ„ํš๋ฒ• ๋ฌธ์ œ์—์„œ ๋ถ€๋ถ„ ๋ฌธ์ œ ํ•ด๊ฒฐ

์žฌ๊ท€๋Š” ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ณ , ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ์ง๊ด€์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

Linear Search

์„ ํ˜• ๊ฒ€์ƒ‰(Linear Search)์€ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋กœ, ๋ฐฐ์—ด์ด๋‚˜ ๋ฆฌ์ŠคํŠธ์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์—์„œ ํŠน์ • ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ์š”์†Œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋น„๊ตํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„ ํ˜• ๊ฒ€์ƒ‰์€ ๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์€ ๋ฐ์ดํ„ฐ์…‹์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

์„ ํ˜• ๊ฒ€์ƒ‰์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ˆœ์ฐจ์ ์œผ๋กœ ๋น„๊ต: ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰ ์š”์†Œ๊นŒ์ง€ ์ˆœ์ฐจ์ ์œผ๋กœ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  2. ์ผ์น˜ํ•˜๋Š” ์š”์†Œ ์ฐพ๊ธฐ: ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ์™€ ์ผ์น˜ํ•˜๋Š” ์š”์†Œ๋ฅผ ์ฐพ์œผ๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ผ์น˜ํ•˜๋Š” ์š”์†Œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ: ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•œ ํ›„์—๋„ ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด -1์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ์„ ํ˜• ๊ฒ€์ƒ‰์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function linearSearch(arr, target) {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === target) {
      return i; // ์š”์†Œ๋ฅผ ์ฐพ์œผ๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜
    }
  }
  return -1; // ์š”์†Œ๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด -1 ๋ฐ˜ํ™˜
}

let arr = [5, 3, 8, 4, 2];
console.log(linearSearch(arr, 8)); // 2
console.log(linearSearch(arr, 7)); // -1

์‹œ๊ฐ„ ๋ณต์žก๋„

์„ ํ˜• ๊ฒ€์ƒ‰์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n)
    • ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(1)
    • ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๊ฐ€ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ์ธ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋‹จ์ˆœํ•จ: ์„ ํ˜• ๊ฒ€์ƒ‰์€ ๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.
  2. ๋น„๊ต ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰(Comparison Search): ์š”์†Œ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋น„๊ตํ•˜์—ฌ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ •๋ ฌ ์—ฌ๋ถ€์™€ ๋ฌด๊ด€: ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€ ์•Š์•„๋„ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  4. ์ œ์ž๋ฆฌ ๊ฒ€์ƒ‰(In-place Search): ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์žฅ์ 

  1. ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ : ๊ตฌํ˜„์ด ์‰ฝ๊ณ  ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค.
  2. ์ •๋ ฌ ํ•„์š” ์—†์Œ: ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€ ์•Š์•„๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ž‘์€ ๋ฐ์ดํ„ฐ์…‹์— ์œ ์šฉ: ์ž‘์€ ๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•ด์„œ๋Š” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ๋น„ํšจ์œจ์„ฑ: ํฐ ๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•ด์„œ๋Š” ๋น„ํšจ์œจ์ ์ด๋ฉฐ, ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์‹œ๊ฐ„ ๋ณต์žก๋„: ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n)์œผ๋กœ, ์š”์†Œ์˜ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ฒ€์ƒ‰ ์‹œ๊ฐ„์ด ์„ ํ˜•์ ์œผ๋กœ ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์„ ํ˜• ๊ฒ€์ƒ‰์€ ๊ฐ„๋‹จํ•˜๊ณ  ๊ตฌํ˜„์ด ์‰ฌ์šด ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ์ž‘์€ ๋ฐ์ดํ„ฐ์…‹์ด๋‚˜ ์ •๋ ฌ๋˜์ง€ ์•Š์€ ๋ฆฌ์ŠคํŠธ์— ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํฐ ๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•ด์„œ๋Š” ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง€๋ฏ€๋กœ, ์ด์ง„ ๊ฒ€์ƒ‰(Binary Search)๊ณผ ๊ฐ™์€ ๋” ํšจ์œจ์ ์ธ ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด์ง„ ๊ฒ€์ƒ‰์€ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ ํ›จ์”ฌ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

Naive String Search

Naive String Search๋Š” ๋ฌธ์ž์—ด ๋‚ด์—์„œ ํŠน์ • ํŒจํ„ด์„ ์ฐพ๊ธฐ ์œ„ํ•œ ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ ์ธ ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํ…์ŠคํŠธ์˜ ๊ฐ ์œ„์น˜์—์„œ ํŒจํ„ด์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ๋งค์šฐ ์ง๊ด€์ ์ด์ง€๋งŒ, ๋น„ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๊ธด ํ…์ŠคํŠธ์™€ ํŒจํ„ด์˜ ๊ฒฝ์šฐ ๋” ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

Naive String Search์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ํ…์ŠคํŠธ์˜ ๊ฐ ์œ„์น˜์—์„œ ํŒจํ„ด ํ™•์ธ: ํ…์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ, ํŒจํ„ด์˜ ๊ธธ์ด๋งŒํผ์˜ ๋ฌธ์ž๊ฐ€ ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  2. ์ผ์น˜ ์—ฌ๋ถ€ ํŒ๋‹จ: ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์œ„์น˜๋ฅผ ๊ธฐ๋กํ•˜๊ณ , ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ ์œ„์น˜๋กœ ์ด๋™ํ•˜์—ฌ ๋‹ค์‹œ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐ˜๋ณต: ํ…์ŠคํŠธ์˜ ๋๊นŒ์ง€ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ Naive String Search์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function naiveStringSearch(longer, shorter) {
  let cnt = 0;

  for (let i = 0; i < longer.length; i++) {
    for (let j = 0; j < shorter.length; j++) {
      if (shorter[j] !== longer[i + j]) break;
      if (j === shorter.length - 1) cnt++;
    }
  }

  return cnt;
}

naiveStringSearch('omaomggfaomg', 'omg'); // 1

์‹œ๊ฐ„ ๋ณต์žก๋„

Naive String Search์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n * m)
    • ์—ฌ๊ธฐ์„œ n์€ ํ…์ŠคํŠธ์˜ ๊ธธ์ด, m์€ ํŒจํ„ด์˜ ๊ธธ์ด์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋‹จ์ˆœํ•จ: ๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค.
  2. ๋น„๊ต ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰: ํŒจํ„ด์˜ ๊ฐ ๋ฌธ์ž์™€ ํ…์ŠคํŠธ์˜ ๊ฐ ์œ„์น˜๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  3. ์ •๋ ฌ ํ•„์š” ์—†์Œ: ํ…์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  4. ์ œ์ž๋ฆฌ ๊ฒ€์ƒ‰: ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์žฅ์ 

  1. ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„: ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋งค์šฐ ์ง๊ด€์ ์ด๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  2. ๋ณดํŽธ์  ์‚ฌ์šฉ: ํ…์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์„ ํ•„์š”๊ฐ€ ์—†์–ด ๋‹ค์–‘ํ•œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ๋น„ํšจ์œจ์„ฑ: ๊ธด ํ…์ŠคํŠธ์™€ ํŒจํ„ด์— ๋Œ€ํ•ด์„œ๋Š” ๋งค์šฐ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
  2. ์‹œ๊ฐ„ ๋ณต์žก๋„: ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n * m)์œผ๋กœ, ๋” ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋น„ํ•ด ๋Š๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ์„ ๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

๊ธด ํ…์ŠคํŠธ๋‚˜ ํŒจํ„ด์„ ๋‹ค๋ฃฐ ๋•Œ ๋” ํšจ์œจ์ ์ธ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. Knuth-Morris-Pratt (KMP) ์•Œ๊ณ ๋ฆฌ์ฆ˜: ํŒจํ„ด ๋‚ด์—์„œ์˜ ๋ถ€๋ถ„ ์ผ์น˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.
  2. Boyer-Moore ์•Œ๊ณ ๋ฆฌ์ฆ˜: ํŒจํ„ด์„ ๋’ค์—์„œ ์•ž์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋” ํฐ ํญ์œผ๋กœ ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  3. Rabin-Karp ์•Œ๊ณ ๋ฆฌ์ฆ˜: ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒจํ„ด๊ณผ ํ…์ŠคํŠธ์˜ ์„œ๋ธŒ์ŠคํŠธ๋ง์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

Naive String Search๋Š” ๋‹จ์ˆœํ•˜๊ณ  ๊ตฌํ˜„์ด ์‰ฌ์šด ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์งง์€ ํ…์ŠคํŠธ์™€ ํŒจํ„ด์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉํ•˜์ง€๋งŒ, ๊ธด ํ…์ŠคํŠธ์™€ ํŒจํ„ด์„ ๋‹ค๋ฃฐ ๋•Œ๋Š” ๋” ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํšจ์œจ์ ์ธ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰์„ ์œ„ํ•ด KMP, Boyer-Moore, Rabin-Karp์™€ ๊ฐ™์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ณต๋ถ€ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

Binary Search

์ด์ง„ ํƒ์ƒ‰(Binary Search)์€ ํšจ์œจ์ ์ธ ๊ฒ€์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ์ •๋ ฌ๋œ ๋ฐฐ์—ด์ด๋‚˜ ๋ฆฌ์ŠคํŠธ์—์„œ ํŠน์ • ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด์ง„ ํƒ์ƒ‰์€ ๋งค๋ฒˆ ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ๋ฐ˜์œผ๋กœ ์ค„์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

์ด์ง„ ํƒ์ƒ‰์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ค‘๊ฐ„ ์š”์†Œ ์„ ํƒ: ๊ฒ€์ƒ‰ ๋ฒ”์œ„์˜ ์ค‘๊ฐ„ ์š”์†Œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  2. ๋น„๊ต: ์ค‘๊ฐ„ ์š”์†Œ์™€ ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
    • ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ: ์š”์†Œ๋ฅผ ์ฐพ์œผ๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    • ์ž‘์€ ๊ฒฝ์šฐ: ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๊ฐ€ ์ค‘๊ฐ„ ์š”์†Œ๋ณด๋‹ค ์ž‘์œผ๋ฉด, ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ์ค‘๊ฐ„ ์š”์†Œ์˜ ์™ผ์ชฝ ๋ถ€๋ถ„์œผ๋กœ ์ค„์ž…๋‹ˆ๋‹ค.
    • ํฐ ๊ฒฝ์šฐ: ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๊ฐ€ ์ค‘๊ฐ„ ์š”์†Œ๋ณด๋‹ค ํฌ๋ฉด, ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ์ค‘๊ฐ„ ์š”์†Œ์˜ ์˜ค๋ฅธ์ชฝ ๋ถ€๋ถ„์œผ๋กœ ์ค„์ž…๋‹ˆ๋‹ค.
  3. ๋ฐ˜๋ณต: ๊ฒ€์ƒ‰ ๋ฒ”์œ„๊ฐ€ ์—†์„ ๋•Œ๊นŒ์ง€ 1~2๋ฒˆ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.
  4. ์ฐพ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ: ๊ฒ€์ƒ‰ ๋ฒ”์œ„๊ฐ€ ์—†์–ด์ง€๋ฉด, ์š”์†Œ๊ฐ€ ๋ฆฌ์ŠคํŠธ์— ์—†๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ -1์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ์ด์ง„ ํƒ์ƒ‰์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function binarySearch(arr, target) {
  var start = 0;
  var end = arr.length - 1;
  var middle = Math.floor((start + end) / 2);

  while (arr[middle] !== target && start <= end) {
    if (target < arr[middle]) {
      end = middle - 1;
    } else {
      start = middle + 1;
    }
    middle = Math.floor((start + end) / 2);
  }
  if (arr[middle] === target) {
    return middle;
  }
  return -1;
}

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(binarySearch(arr, 7)); // 6
console.log(binarySearch(arr, 11)); // -1

์‹œ๊ฐ„ ๋ณต์žก๋„

์ด์ง„ ํƒ์ƒ‰์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(log n)
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(log n)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(1)
    • ๊ฒ€์ƒ‰ํ•˜๋ ค๋Š” ์š”์†Œ๊ฐ€ ์ค‘๊ฐ„ ์š”์†Œ์ธ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ํšจ์œจ์„ฑ: ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
  2. ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ ํ•„์š”: ์ด์ง„ ํƒ์ƒ‰์€ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์–ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋น„๊ต ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰(Comparison Search): ์š”์†Œ๋“ค์„ ๋น„๊ตํ•˜์—ฌ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ 

  1. ๋น ๋ฅธ ๊ฒ€์ƒ‰ ์†๋„: ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ, ์š”์†Œ์˜ ์ˆ˜๊ฐ€ ๋งŽ์•„๋„ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ œ์ž๋ฆฌ ๊ฒ€์ƒ‰(In-place Search): ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ์ •๋ ฌ ํ•„์š”: ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์–ด์•ผ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ตฌํ˜„ ๋ณต์žก์„ฑ: ์„ ํ˜• ๊ฒ€์ƒ‰์— ๋น„ํ•ด ๊ตฌํ˜„์ด ์กฐ๊ธˆ ๋” ๋ณต์žกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฌ๊ท€์  ๊ตฌํ˜„

์ด์ง„ ํƒ์ƒ‰์€ ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์™ธ์—๋„ ์žฌ๊ท€์ ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์žฌ๊ท€์  ์ด์ง„ ํƒ์ƒ‰์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function binarySearchRecursive(arr, target, left = 0, right = arr.length - 1) {
  if (left > right) {
    return -1; // ์š”์†Œ๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด -1 ๋ฐ˜ํ™˜
  }

  let mid = Math.floor((left + right) / 2);

  if (arr[mid] === target) {
    return mid; // ์š”์†Œ๋ฅผ ์ฐพ์œผ๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜ํ™˜
  } else if (arr[mid] < target) {
    return binarySearchRecursive(arr, target, mid + 1, right); // ์˜ค๋ฅธ์ชฝ ๋ถ€๋ถ„์„ ๊ฒ€์ƒ‰
  } else {
    return binarySearchRecursive(arr, target, left, mid - 1); // ์™ผ์ชฝ ๋ถ€๋ถ„์„ ๊ฒ€์ƒ‰
  }
}

let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(binarySearchRecursive(arr, 7)); // 6
console.log(binarySearchRecursive(arr, 11)); // -1

๊ฒฐ๋ก 

์ด์ง„ ํƒ์ƒ‰์€ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์—์„œ ๋งค์šฐ ํšจ์œจ์ ์œผ๋กœ ์š”์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(log n)์œผ๋กœ, ํฐ ๋ฐ์ดํ„ฐ์…‹์—์„œ๋„ ๋น ๋ฅด๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ œํ•œ์ด ์žˆ์ง€๋งŒ, ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒฝ์šฐ ์ด์ง„ ํƒ์ƒ‰์€ ๋งค์šฐ ์œ ์šฉํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

Bubble Sort

๋ฒ„๋ธ” ์ •๋ ฌ(Bubble Sort)์€ ๊ฐ„๋‹จํ•œ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋กœ, ์ธ์ ‘ํ•œ ๋‘ ์š”์†Œ๋ฅผ ๋น„๊ตํ•˜์—ฌ ํ•„์š”์— ๋”ฐ๋ผ ์œ„์น˜๋ฅผ ๋ฐ”๊พธ๋ฉด์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ฒ„๋ธ” ์ •๋ ฌ์˜ ์ด๋ฆ„์€ ๊ฐ€์žฅ ํฐ ์š”์†Œ๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฆฌ์ŠคํŠธ์˜ ๋์œผ๋กœ "๋ถ€ํ’€์–ด ์˜ค๋ฅด๋Š”" ๊ณผ์ •์—์„œ ์œ ๋ž˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

๋ฒ„๋ธ” ์ •๋ ฌ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๋น„๊ต ๋ฐ ๊ตํ™˜: ๋ฆฌ์ŠคํŠธ์˜ ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์ธ์ ‘ํ•œ ๋‘ ์š”์†Œ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๊ฐ€ ๋‘ ๋ฒˆ์งธ ์š”์†Œ๋ณด๋‹ค ํฌ๋ฉด ๋‘ ์š”์†Œ์˜ ์œ„์น˜๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
  2. ๋ฐ˜๋ณต: ๋ฆฌ์ŠคํŠธ ๋๊นŒ์ง€ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋ฉด ๊ฐ€์žฅ ํฐ ์š”์†Œ๊ฐ€ ๋ฆฌ์ŠคํŠธ์˜ ๋์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐ˜๋ณต ๊ฐ์†Œ: ๋ฆฌ์ŠคํŠธ ๋์— ๊ฐ€์žฅ ํฐ ์š”์†Œ๊ฐ€ ๊ณ ์ •๋˜๋ฉด ๋‹ค์Œ ๋ฐ˜๋ณต์—์„œ๋Š” ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์š”์†Œ๋ฅผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  4. ์ •๋ ฌ ์™„๋ฃŒ: ๋” ์ด์ƒ ๊ตํ™˜์ด ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ๊นŒ์ง€ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ๋ฒ„๋ธ” ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function bubbleSort(arr) {
  let swaps = true;
  for (let i = arr.length; i > 0; i--) {
    for (let j = 0; j < i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
        swaps = false;
      }
    }
    if (swaps) break;
  }
  return arr;
}

console.log(bubbleSort([1, 6, 3, 10, 2, 15]));

// [ 1, 6, 3, 10, 2, 15 ]
// [ 1, 3, 6, 10, 2, 15 ]
// [ 1, 3, 6, 2, 10, 15 ]
// [ 1, 3, 2, 6, 10, 15 ]
// [ 1, 2, 3, 6, 10, 15 ]

bubble sort

์‹œ๊ฐ„ ๋ณต์žก๋„

๋ฒ„๋ธ” ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
    • ๋ฆฌ์ŠคํŠธ๊ฐ€ ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•˜๊ณ  ๊ตํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n)
    • ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ํ•œ ๋ฒˆ์˜ ๋ฐ˜๋ณต๋งŒ์œผ๋กœ ์ •๋ ฌ์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋‹จ์ˆœํ•จ: ๋ฒ„๋ธ” ์ •๋ ฌ์€ ๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.
  2. ์•ˆ์ •์„ฑ: ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋น„ํšจ์œจ์„ฑ: ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)๋กœ, ํฐ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋“œ๋ฌธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์ตœ์ ํ™”

๋ฒ„๋ธ” ์ •๋ ฌ์€ ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ๋น„๊ต๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์–ด๋–ค ๋ฐ˜๋ณต์—์„œ ๊ตํ™˜์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒƒ์ด๋ฏ€๋กœ ์ •๋ ฌ์„ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function optimizedBubbleSort(arr) {
  let n = arr.length;
  let swapped;

  do {
    swapped = false;
    for (let i = 0; i < n - 1; i++) {
      if (arr[i] > arr[i + 1]) {
        let temp = arr[i];
        arr[i] = arr[i + 1];
        arr[i + 1] = temp;
        swapped = true;
      }
    }
    n--;
  } while (swapped);

  return arr;
}

let arr = [3, 2, 1, 4, 5];
console.log(optimizedBubbleSort(arr)); // [1, 2, 3, 4, 5]

์ด ์ตœ์ ํ™”๋Š” ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ O(n)์œผ๋กœ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๋ฒ„๋ธ” ์ •๋ ฌ์€ ์ดํ•ดํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฌ์šด ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๊ต์œก์šฉ์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹œ๊ฐ„ ๋ณต์žก๋„ ์ธก๋ฉด์—์„œ ๋น„ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ๋ฐฐ์—ด์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ํ€ต ์ •๋ ฌ(Quick Sort), ๋ณ‘ํ•ฉ ์ •๋ ฌ(Merge Sort), ํž™ ์ •๋ ฌ(Heap Sort)๊ณผ ๊ฐ™์€ ๋” ํšจ์œจ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Selection Sort

์„ ํƒ ์ •๋ ฌ(Selection Sort)์€ ๋‹จ์ˆœํ•œ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋กœ, ๋ฆฌ์ŠคํŠธ์—์„œ ๊ฐ€์žฅ ์ž‘์€ ์š”์†Œ๋ฅผ ์ฐพ์•„ ๋งจ ์•ž์˜ ์š”์†Œ์™€ ๊ตํ™˜ํ•˜๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜์—ฌ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„ ํƒ ์ •๋ ฌ์€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)์œผ๋กœ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

์„ ํƒ ์ •๋ ฌ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ์ตœ์†Œ๊ฐ’ ์ฐพ๊ธฐ: ๋ฆฌ์ŠคํŠธ์—์„œ ํ˜„์žฌ ์œ„์น˜๋ถ€ํ„ฐ ๋๊นŒ์ง€ ํƒ์ƒ‰ํ•˜์—ฌ ๊ฐ€์žฅ ์ž‘์€ ์š”์†Œ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  2. ๊ตํ™˜: ๊ฐ€์žฅ ์ž‘์€ ์š”์†Œ๋ฅผ ํ˜„์žฌ ์œ„์น˜์˜ ์š”์†Œ์™€ ๊ตํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐ˜๋ณต: ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์œ„์น˜์— ๋Œ€ํ•ด ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ์„ ํƒ ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function swap(arr, idx1, idx2) {
  let temp = arr[idx1];
  arr[idx1] = arr[idx2];
  arr[idx2] = temp;
}

function selectionSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    let tempIdx = i;

    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[tempIdx]) {
        tempIdx = j;
      }
    }

    if (i !== tempIdx) swap(arr, i, tempIdx);
  }
  return arr;
}

console.log(selectionSort([0, 2, 34, 22, 10, 19, 17]));

// [ 0, 2, 10, 22, 34, 19, 17 ]
// [ 0, 2, 10, 17, 34, 19, 22 ]
// [ 0, 2, 10, 17, 19, 34, 22 ]
// [ 0, 2, 10, 17, 19, 22, 34 ]
// [ 0, 2, 10, 17, 19, 22, 34 ]

bubble sort

์‹œ๊ฐ„ ๋ณต์žก๋„

์„ ํƒ ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
    • ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฐ˜๋ณต๋ฌธ์ด ์ค‘์ฒฉ๋˜์–ด ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)์ž…๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
    • ์ด๋ฏธ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์—์„œ๋„ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ์—ฌ์ „ํžˆ O(n^2)์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋‹จ์ˆœํ•จ: ์„ ํƒ ์ •๋ ฌ์€ ์ดํ•ดํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๊ธฐ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  2. ์ œ์ž๋ฆฌ ์ •๋ ฌ(In-place Sort): ๋ณ„๋„์˜ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ฃผ์–ด์ง„ ๋ฐฐ์—ด ๋‚ด์—์„œ ์ •๋ ฌ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  3. ์•ˆ์ •์„ฑ: ์„ ํƒ ์ •๋ ฌ์€ ์•ˆ์ •์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. ๋น„ํšจ์œจ์„ฑ: ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)์œผ๋กœ, ํฐ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋“œ๋ญ…๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์„ ํƒ ์ •๋ ฌ์€ ๊ต์œก ๋ชฉ์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๋‹จ์ˆœํ•œ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ์‹œ๊ฐ„ ๋ณต์žก๋„ ์ธก๋ฉด์—์„œ ๋น„ํšจ์œจ์ ์ด๋ฏ€๋กœ ์‹ค์ œ๋กœ๋Š” ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ๋ฐฐ์—ด์„ ์ œ์™ธํ•˜๊ณ ๋Š” ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ํ€ต ์ •๋ ฌ(Quick Sort), ๋ณ‘ํ•ฉ ์ •๋ ฌ(Merge Sort), ํž™ ์ •๋ ฌ(Heap Sort)๊ณผ ๊ฐ™์€ ๋” ํšจ์œจ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Insertion Sort

์‚ฝ์ž… ์ •๋ ฌ(Insertion Sort)์€ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ค‘ ํ•˜๋‚˜๋กœ, ๋ฐฐ์—ด์„ ๋ถ€๋ถ„์ ์œผ๋กœ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ ์ƒˆ๋กœ์šด ์š”์†Œ๋ฅผ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์‚ฝ์ž…ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์‚ฝ์ž… ์ •๋ ฌ์€ ์ž‘์€ ๋ฐ์ดํ„ฐ ์„ธํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ํšจ์œจ์ ์ด๊ณ , ๊ฑฐ์˜ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ๋„ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

์‚ฝ์ž… ์ •๋ ฌ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๋ถ€๋ถ„ ์ •๋ ฌ ์œ ์ง€: ๋ฐฐ์—ด์˜ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋Š” ์ด๋ฏธ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ๊ฐ„์ฃผํ•˜๊ณ , ๋‘ ๋ฒˆ์งธ ์š”์†Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ๋ฐฐ์—ด์„ ๋ถ€๋ถ„์ ์œผ๋กœ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. ์‚ฝ์ž… ์œ„์น˜ ์ฐพ๊ธฐ: ํ˜„์žฌ ์š”์†Œ๋ฅผ ์ด๋ฏธ ์ •๋ ฌ๋œ ๋ถ€๋ถ„ ๋ฐฐ์—ด๊ณผ ๋น„๊ตํ•˜์—ฌ ์ ์ ˆํ•œ ์œ„์น˜๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  3. ์‚ฝ์ž…: ํ˜„์žฌ ์š”์†Œ๋ฅผ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  4. ๋ฐ˜๋ณต: ๋ฐฐ์—ด์˜ ๋ชจ๋“  ์š”์†Œ์— ๋Œ€ํ•ด ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ์‚ฝ์ž… ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function insertionSort(arr) {
  var currentVal;

  for (var i = 1; i < arr.length; i++) {
    currentVal = arr[i];

    for (var j = i - 1; j >= 0 && arr[j] > currentVal; j--) {
      arr[j + 1] = arr[j];
    }
    arr[j + 1] = currentVal;
  }
  return arr;
}

console.log(insertionSort([2, 1, 9, 76, 4]));

// currentnValue: 1 ,  [ 1, 2, 9, 76, 4 ]
// currentnValue: 9 ,  [ 1, 2, 9, 76, 4 ]
// currentnValue: 76 , [ 1, 2, 9, 76, 4 ]
// currentnValue: 4 ,  [ 1, 2, 4, 9, 76 ]

//

bubble sort

์‹œ๊ฐ„ ๋ณต์žก๋„

์‚ฝ์ž… ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
    • ๋ฐฐ์—ด์ด ์—ญ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ๋ชจ๋“  ์š”์†Œ๋ฅผ ๋น„๊ตํ•˜๊ณ  ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n)
    • ๋ฐฐ์—ด์ด ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ํ•œ ๋ฒˆ์˜ ๋น„๊ต๋งŒ์œผ๋กœ ์ •๋ ฌ์ด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋‹จ์ˆœํ•จ: ์‚ฝ์ž… ์ •๋ ฌ์€ ์ดํ•ดํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๊ธฐ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  2. ์ œ์ž๋ฆฌ ์ •๋ ฌ(In-place Sort): ๋ณ„๋„์˜ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ฃผ์–ด์ง„ ๋ฐฐ์—ด ๋‚ด์—์„œ ์ •๋ ฌ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค.
  3. ์•ˆ์ •์„ฑ: ์‚ฝ์ž… ์ •๋ ฌ์€ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  4. ํšจ์œจ์„ฑ: ์‚ฝ์ž… ์ •๋ ฌ์€ ์ž‘์€ ๋ฐฐ์—ด์ด๋‚˜ ๊ฑฐ์˜ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํฐ ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ๋Š” ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์‚ฝ์ž… ์ •๋ ฌ์€ ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์ž‘์€ ๋ฐ์ดํ„ฐ ์„ธํŠธ๋‚˜ ๊ฑฐ์˜ ์ •๋ ฌ๋œ ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ๋Š” ๋งค์šฐ ํšจ์œจ์ ์ด๋ฉฐ, ์•ˆ์ •์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)์ด๊ธฐ ๋•Œ๋ฌธ์— ํฐ ๋ฐฐ์—ด์— ๋Œ€ํ•ด์„œ๋Š” ๋น„ํšจ์œจ์ ์ด๋ฉฐ, ์ด ๊ฒฝ์šฐ ํ€ต ์ •๋ ฌ(Quick Sort), ๋ณ‘ํ•ฉ ์ •๋ ฌ(Merge Sort), ํž™ ์ •๋ ฌ(Heap Sort)๊ณผ ๊ฐ™์€ ๋” ํšจ์œจ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Merge Sort

๋ณ‘ํ•ฉ ์ •๋ ฌ(Merge Sort)์€ Divide and Conquer ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ํšจ์œจ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ๋ณ‘ํ•ฉ ์ •๋ ฌ์€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆ„์–ด ๊ฐ๊ฐ์„ ์žฌ๊ท€์ ์œผ๋กœ ์ •๋ ฌํ•˜๊ณ , ์ •๋ ฌ๋œ ๋ถ€๋ถ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ•ฉ์ณ์„œ ์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์•ˆ์ •์ ์ด๊ณ , ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n log n)์œผ๋กœ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

๋ณ‘ํ•ฉ ์ •๋ ฌ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ๋ถ„ํ• (Divide): ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘ ๊ฐœ์˜ ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.
  2. ์ •๋ณต(Conquer): ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋ณ‘ํ•ฉ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฒฐํ•ฉ(Combine): ๋‘ ๊ฐœ์˜ ์ •๋ ฌ๋œ ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ•˜๋‚˜์˜ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ‘ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ๋ณ‘ํ•ฉ ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function merge(arr1, arr2) {
  let idx1 = 0;
  let idx2 = 0;
  let result = [];

  while (idx1 < arr1.length && idx2 < arr2.length) {
    if (arr1[idx1] < arr2[idx2]) {
      result.push(arr1[idx1]);
      idx1++;
    } else {
      result.push(arr2[idx2]);
      idx2++;
    }
  }

  // Remaining elements from arr1
  while (idx1 < arr1.length) {
    result.push(arr1[idx1]);
    idx1++;
  }

  // Remaining elements from arr2
  while (idx2 < arr2.length) {
    result.push(arr2[idx2]);
    idx2++;
  }

  return result;
}

function mergeSort(arr) {
  if (arr.length <= 1) return arr;

  let mid = Math.floor(arr.length / 2);
  let left = mergeSort(arr.slice(0, mid));
  let right = mergeSort(arr.slice(mid));

  return merge(left, right);
}

console.log(mergeSort([8, 3, 5, 4, 7, 6, 1, 2]));

// [ 8, 3, 5, 4, 7, 6, 1, 2 ]
// [ 8, 3, 5, 4 ] [ 7, 6, 1, 2 ]
// [ 8, 3 ] [ 5, 4 ] [ 7, 6 ] [ 1, 2 ]
// [ 8 ] [ 3 ] [ 5 ] [ 4 ] [ 7 ] [ 6 ] [ 1 ] [ 2 ]
// [ 3, 8 ] [ 4, 5 ] [ 6, 7 ] [ 1, 2 ]
// [ 3, 4, 5, 8 ] [ 1, 2, 6, 7 ]
// [ 1, 2, 3, 4, 5, 6, 7, 8 ]

bubble sort

์‹œ๊ฐ„ ๋ณต์žก๋„

๋ณ‘ํ•ฉ ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n)
    • ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ฐ˜์œผ๋กœ ๋‚˜๋ˆ„๊ณ , ๊ฐ ๋‹จ๊ณ„์—์„œ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐ O(n) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n)
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n)

ํŠน์ง•

  1. ์•ˆ์ •์„ฑ: ๋ณ‘ํ•ฉ ์ •๋ ฌ์€ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ œ์ž๋ฆฌ ์ •๋ ฌ์ด ์•„๋‹˜(Not In-place Sort): ๋ณ‘ํ•ฉ ์ •๋ ฌ์€ ์ถ”๊ฐ€์ ์ธ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ‘ํ•ฉ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ถ„ํ•  ์ •๋ณต ๊ธฐ๋ฒ•(Divide and Conquer): ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ถ„ํ• ํ•˜๊ณ , ๊ฐ๊ฐ์„ ์ •๋ ฌํ•œ ํ›„ ๋ณ‘ํ•ฉํ•˜์—ฌ ์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ 

  1. ์•ˆ์ •์ ์ธ ์ •๋ ฌ: ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  2. ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์‹œ๊ฐ„ ๋ณต์žก๋„: ์ตœ์„ , ํ‰๊ท , ์ตœ์•…์˜ ๊ฒฝ์šฐ ๋ชจ๋‘ O(n log n)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
  3. ์™ธ๋ถ€ ์ •๋ ฌ ๊ฐ€๋Šฅ: ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋””์Šคํฌ์—์„œ ์ •๋ ฌํ•  ๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ: ๋ณ‘ํ•ฉ ์ •๋ ฌ์€ ์ถ”๊ฐ€์ ์ธ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ‘ํ•ฉ์„ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋Š˜์–ด๋‚ฉ๋‹ˆ๋‹ค.
  2. ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ: ๋ฐ์ดํ„ฐ์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋น„๊ต ์—ฐ์‚ฐ์ด ๋งŽ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๋ณ‘ํ•ฉ ์ •๋ ฌ์€ ํšจ์œจ์ ์ด๊ณ  ์•ˆ์ •์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ํŠนํžˆ ํฐ ๋ฐ์ดํ„ฐ ์„ธํŠธ๋‚˜ ์™ธ๋ถ€ ์ •๋ ฌ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์œผ๋ฏ€๋กœ, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ์ค‘์š”ํ•œ ํ™˜๊ฒฝ์—์„œ๋Š” ํ€ต ์ •๋ ฌ(Quick Sort)๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Quick Sort

ํ€ต ์ •๋ ฌ(Quick Sort)์€ Divide and Conquer ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋งค์šฐ ํšจ์œจ์ ์ธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ํ‰๊ท ์ ์œผ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์‹œ๊ฐ„ ๋ณต์žก๋„์ธ O(n log n)์„ ๊ฐ€์ง€๋ฉฐ, ์ œ์ž๋ฆฌ ์ •๋ ฌ(In-place Sort) ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ํ€ต ์ •๋ ฌ์€ ๋ฆฌ์ŠคํŠธ์—์„œ ํ”ผ๋ฒ—(pivot) ์š”์†Œ๋ฅผ ์„ ํƒํ•˜๊ณ , ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘ ๊ฐœ์˜ ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๋กœ ๋‚˜๋ˆ„๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜์—ฌ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

ํ€ต ์ •๋ ฌ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. ํ”ผ๋ฒ— ์„ ํƒ: ๋ฆฌ์ŠคํŠธ์—์„œ ํ”ผ๋ฒ— ์š”์†Œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ถ„ํ• : ํ”ผ๋ฒ—์„ ๊ธฐ์ค€์œผ๋กœ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘ ๊ฐœ์˜ ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ถ„ํ• ํ•ฉ๋‹ˆ๋‹ค. ํ”ผ๋ฒ—๋ณด๋‹ค ์ž‘์€ ์š”์†Œ๋“ค์€ ํ”ผ๋ฒ—์˜ ์™ผ์ชฝ์œผ๋กœ, ํ”ผ๋ฒ—๋ณด๋‹ค ํฐ ์š”์†Œ๋“ค์€ ํ”ผ๋ฒ—์˜ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  3. ์žฌ๊ท€ ํ˜ธ์ถœ: ๋ถ„ํ• ๋œ ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด ํ€ต ์ •๋ ฌ์„ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ฒฐํ•ฉ: ํ•˜์œ„ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ •๋ ฌ๋˜๋ฉด ์ด๋“ค์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์ „์ฒด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ํ€ต ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

function swap(arr, idx1, idx2) {
  let temp = arr[idx1];
  arr[idx1] = arr[idx2];
  arr[idx2] = temp;
}

function pivot(arr, start = 0, end = arr.length + 1) {
  var pivot = arr[start];
  var swapIdx = start;

  for (var i = start + 1; i < arr.length; i++) {
    if (pivot > arr[i]) {
      swapIdx++;
      swap(arr, swapIdx, i);
    }
  }
  swap(arr, start, swapIdx);
  return swapIdx;
}

console.log(pivot([5, 2, 1, 8, 4, 7, 6, 3])); // 3

function quickSort(arr, left = 0, right = arr.length - 1) {
  if (left < right) {
    let pivotIndex = pivot(arr, left, right);

    // left
    quickSort(arr, left, pivotIndex - 1);
    // right
    quickSort(arr, pivotIndex + 1, right);
  }
  return arr;
}

bubble sort

์‹œ๊ฐ„ ๋ณต์žก๋„

ํ€ต ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n^2)
    • ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ๋‚˜ ํ”ผ๋ฒ—์ด ์ตœ์†Ÿ๊ฐ’์ด๋‚˜ ์ตœ๋Œ“๊ฐ’์œผ๋กœ ์„ ํƒ๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n)
    • ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„ํ• ๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n)
    • ํ”ผ๋ฒ—์ด ํ•ญ์ƒ ๋ฆฌ์ŠคํŠธ์˜ ์ค‘์•™๊ฐ’์„ ์„ ํƒํ•˜์—ฌ ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„ํ• ๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ์ œ์ž๋ฆฌ ์ •๋ ฌ(In-place Sort): ํ€ต ์ •๋ ฌ์€ ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  2. ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ(Comparison Sort): ์š”์†Œ๋“ค์„ ๋น„๊ตํ•˜์—ฌ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ถˆ์•ˆ์ • ์ •๋ ฌ(Unstable Sort): ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

ํ€ต ์ •๋ ฌ์€ ํ‰๊ท ์ ์œผ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ๋Œ€๋ถ€๋ถ„์˜ ์‹ค์šฉ์ ์ธ ์ •๋ ฌ ์ž‘์—…์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ์ž๋ฆฌ ์ •๋ ฌ์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ์ ์–ด ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ”ผ๋ฒ— ์„ ํƒ ์ตœ์ ํ™”์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Radix Sort

Radix Sort(๊ธฐ์ˆ˜ ์ •๋ ฌ)์€ ์ •์ˆ˜๋‚˜ ๋ฌธ์ž์—ด์˜ ์ž๋ฆฟ์ˆ˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ํšจ์œจ์ ์ธ ์ •์ˆ˜ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ฃผ๋กœ ์–‘์˜ ์ •์ˆ˜๋‚˜ ๊ณ ์ • ๊ธธ์ด์˜ ๋ฌธ์ž์—ด์„ ์ •๋ ฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(d * (n + k))๋กœ, ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋ณด๋‹ค ๋” ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ d๋Š” ๋ฐ์ดํ„ฐ์˜ ์ตœ๋Œ€ ์ž๋ฆฟ์ˆ˜, n์€ ์š”์†Œ์˜ ์ˆ˜, k๋Š” ๊ธฐ์ˆ˜(์˜ˆ: 10์ง„๋ฒ•์—์„œ๋Š” 10)์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

๊ธฐ์ˆ˜ ์ •๋ ฌ์€ LSD(Least Significant Digit)์™€ MSD(Most Significant Digit) ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค:

  • LSD ๋ฐฉ์‹: ๊ฐ€์žฅ ์ž‘์€ ์ž๋ฆฟ์ˆ˜๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ํฐ ์ž๋ฆฟ์ˆ˜ ๋ฐฉํ–ฅ์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
  • MSD ๋ฐฉ์‹: ๊ฐ€์žฅ ํฐ ์ž๋ฆฟ์ˆ˜๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ์ž‘์€ ์ž๋ฆฟ์ˆ˜ ๋ฐฉํ–ฅ์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

LSD ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ณผ์ •

  1. ์ตœ๋Œ€ ์ž๋ฆฟ์ˆ˜ ๊ฒฐ์ •: ๋ฐ์ดํ„ฐ ์ค‘ ๊ฐ€์žฅ ํฐ ์ˆ˜์˜ ์ž๋ฆฟ์ˆ˜๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.
  2. ์ž๋ฆฟ์ˆ˜๋ณ„ ์ •๋ ฌ: ๊ฐ ์ž๋ฆฟ์ˆ˜์— ๋Œ€ํ•ด ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, ์•ˆ์ • ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜(์˜ˆ: Counting Sort)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ๊ธฐ์ˆ˜ ์ •๋ ฌ์˜ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค(LSD ๋ฐฉ์‹).

function getDigit(num, place) {
  return Math.floor(Math.abs(num) / Math.pow(10, place)) % 10;
}

function digitCount(num) {
  if (num === 0) return 1;
  return Math.floor(Math.log10(Math.abs(num))) + 1;
}

function mostDigits(nums) {
  let maxDigits = 0;
  for (let num of nums) {
    maxDigits = Math.max(maxDigits, digitCount(num));
  }
  return maxDigits;
}

function radixSort(nums) {
  let maxDigitCount = mostDigits(nums);
  for (let k = 0; k < maxDigitCount; k++) {
    let digitBuckets = Array.from({ length: 10 }, () => []);
    for (let i = 0; i < nums.length; i++) {
      let digit = getDigit(nums[i], k);
      digitBuckets[digit].push(nums[i]);
    }
    nums = [].concat(...digitBuckets);
  }
  return nums;
}

let arr = [170, 45, 75, 90, 802, 24, 2, 66];
console.log(radixSort(arr)); // [2, 24, 45, 66, 75, 90, 170, 802]

radix sort

์‹œ๊ฐ„ ๋ณต์žก๋„

๊ธฐ์ˆ˜ ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ์ตœ์•…์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(d * (n + k))
  • ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„: O(d * (n + k))
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: O(d * (n + k))

์—ฌ๊ธฐ์„œ d๋Š” ๋ฐ์ดํ„ฐ์˜ ์ตœ๋Œ€ ์ž๋ฆฟ์ˆ˜, n์€ ์š”์†Œ์˜ ์ˆ˜, k๋Š” ๊ธฐ์ˆ˜(์˜ˆ: 10์ง„๋ฒ•์—์„œ๋Š” 10)์ž…๋‹ˆ๋‹ค.

ํŠน์ง•

  1. ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ์ด ์•„๋‹˜: ์š”์†Œ๋“ค์„ ๋น„๊ตํ•˜์ง€ ์•Š๊ณ  ์ž๋ฆฟ์ˆ˜๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
  2. ์•ˆ์ • ์ •๋ ฌ: ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ œ์ž๋ฆฌ ์ •๋ ฌ์ด ์•„๋‹˜: ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ 

  1. ํšจ์œจ์„ฑ: ํŠน์ • ์กฐ๊ฑด์—์„œ ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ๋ณด๋‹ค ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์•ˆ์ •์„ฑ: ๋™์ผํ•œ ๊ฐ’์˜ ์š”์†Œ๋“ค์ด ์ž…๋ ฅ ์ˆœ์„œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ์ œ์ž๋ฆฌ ์ •๋ ฌ ์•„๋‹˜: ์ถ”๊ฐ€์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œํ•œ: ์ฃผ๋กœ ์ •์ˆ˜๋‚˜ ๊ณ ์ • ๊ธธ์ด ๋ฌธ์ž์—ด์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ž๋ฆฟ์ˆ˜์— ๋ฏผ๊ฐ: ๋ฐ์ดํ„ฐ์˜ ์ž๋ฆฟ์ˆ˜๊ฐ€ ๋งŽ์„ ๊ฒฝ์šฐ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๊ธฐ์ˆ˜ ์ •๋ ฌ์€ ์ •์ˆ˜๋‚˜ ๊ณ ์ • ๊ธธ์ด ๋ฌธ์ž์—ด์„ ์ •๋ ฌํ•˜๋Š” ๋ฐ ๋งค์šฐ ํšจ์œจ์ ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ๋น„๊ต ๊ธฐ๋ฐ˜ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋น„ํ•ด ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ์ž๋ฆฟ์ˆ˜์— ์ œํ•œ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํฐ ๋ฐ์ดํ„ฐ์…‹์ด๋‚˜ ์ž๋ฆฟ์ˆ˜๊ฐ€ ๋งŽ์€ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ, ๊ธฐ์ˆ˜ ์ •๋ ฌ์˜ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๋ณ‘ํ–‰ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ์ƒํ™ฉ์— ๋งž๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

Single Linked List

JavaScript์—์„œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ(Linked List)๋Š” ๋…ธ๋“œ(Node)๋“ค์ด ํฌ์ธํ„ฐ๋กœ ์—ฐ๊ฒฐ๋œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ, ๊ฐ ๋…ธ๋“œ๋Š” ๋ฐ์ดํ„ฐ์™€ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ๋ฐฐ์—ด(Array)๊ณผ ๋น„๊ตํ–ˆ์„ ๋•Œ ๋ช‡ ๊ฐ€์ง€ ์ฃผ์š” ์ฐจ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…

  • ๋…ธ๋“œ(Node): ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ์š”์†Œ๋Š” ๋…ธ๋“œ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋ฉฐ, ๋ฐ์ดํ„ฐ์™€ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ํ—ค๋“œ(Head): ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
  • ํ…Œ์ผ(Tail): ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.
  • ํฌ์ธํ„ฐ(Next): ๊ฐ ๋…ธ๋“œ๋Š” ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๊ตฌ์กฐ

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ์ฃผ๋กœ ๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Singly Linked List)์™€ ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Doubly Linked List)๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์—์„œ๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ ๋‹ค์Œ ๋…ธ๋“œ๋งŒ ๊ฐ€๋ฆฌํ‚ค์ง€๋งŒ, ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์—์„œ๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ ๋‹ค์Œ ๋…ธ๋“œ์™€ ์ด์ „ ๋…ธ๋“œ๋ฅผ ๋ชจ๋‘ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๊ตฌํ˜„ํ•œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ

๋‹ค์Œ์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
  }
}

class SingleLinkedList {
  constructor() {
    this.length = 0;
    this.head = null;
    this.tail = null;
  }

  push(data) {
    var newNode = new Node(data);
    // list๊ฐ€ ๋น„์–ด ์žˆ๋‹ค๋ฉด, head์™€ tail์„ ๋ชจ๋‘ ์ƒˆ ๋…ธ๋“œ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      // ๊ธฐ์กด node - tail์˜ next์— newNode ์‚ฝ์ž…
      this.tail.next = newNode;
      // ๋ฆฌ์ŠคํŠธ์˜ ๋์ด๋ฏ€๋กœ tail์— newNode ์‚ฝ์ž…
      this.tail = newNode;
    }
    this.length++;
    return this;
  }

  traverse() {
    var current = this.head;
    while (current) {
      console.log('current:', current);
      current = current.next;
    }
  }

  pop() {
    if (!this.head) return undefined;
    let current = this.head;
    let newTail = this.head;

    // while ๋ฌธ ์กฐ๊ฑด ์ดํ•ดํ•˜๊ธฐ
    while (current.next) {
      newTail = current;
      current = current.next;
    }

    this.tail = newTail;
    this.tail.next = null;
    this.length--;

    if (this.length === 0) {
      this.head = null;
      this.tail = null;
    }

    return current;
  }

  shift() {
    // if there are no nodes, return undefined
    // Store the current head property in a variable
    // Set the head property to be the current head's next property
    // Decrement the length by 1
    // Return the value of the node removed

    if (!this.head) return undefined;

    let currentHead = this.head;

    this.head = currentHead.next;
    this.length--;

    if (this.length === 0) {
      this.tail = null;
    }

    return currentHead;
  }

  unshift(data) {
    // This function should accept a value
    // Create a new node using the value passed to the function
    // If there is no head property on the list, set the head and tail to be the newly created node
    let newNode = new Node(data);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.next = this.head;
      this.head = newNode;
    }

    this.length++;

    return this;
  }

  get(index) {
    // ์ธ๋ฑ์Šค๊ฐ€ ์Œ์ˆ˜์ด๊ฑฐ๋‚˜ ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    if (index < 0 || index >= this.length) return null;

    let cnt = 0;
    let currentHead = this.head;

    while (cnt !== index) {
      currentHead = currentHead.next;
      cnt++;
    }

    return currentHead;
  }

  set(index, data) {
    // This function should accept a data an an index
    // Use your get function to find the specific node
    // If the node is not found, return false
    // If the node is found, set the value of that node to be the value passed to the function and return true
    if (index < 0 || index >= this.length) return null;

    let current = this.get(index);
    if (!current) return false;

    current.data = data;

    return true;
  }

  insert(index, data) {
    // If the index is less than zero or greater than the length, return false
    // If the index is the same as the length, push a new node to the end of the list
    // If the index is 0, unshift a new node to the start of the list
    // Otherwise, using the 'get' method, access the node at the index -1
    // Set the next property on that node to be the new node
    // Set the next property on the new node to be the previous next
    // Increment the length
    // Return true;

    if (index < 0 || index > this.length) return false;

    if (index === this.length) {
      // 'push'
      this.push(data);
      return true;
    }

    if (index === 0) {
      // 'unshift'
      this.unshift(data);
      return true;
    }

    // 'normal case'
    let newNode = new Node(data);

    let prevNode = this.get(index - 1);
    newNode.next = prevNode.next;
    prevNode.next = newNode;

    this.length++;
    return true;
  }

  remove(index) {
    // If the index is less than zero or greater than the length, return undefined
    // If the index is the same as the length-1, 'pop'
    // If the index is 0, 'shift'
    // Otherwise, using the 'get' method, access the node at the index -1
    // Set the next property on that node to be the next of the next node
    // Decrement the length
    // Return the value of the node removed

    if (index < 0 || index > this.length) return false;

    if (index === this.length - 1) {
      // 'pop'
      this.pop();
      return true;
    }

    if (index === 0) {
      // 'shift'
      this.shift();
      return true;
    }

    let prevNode = this.get(index - 1);
    let nextNode = prevNode.next.next;

    prevNode.next = nextNode;

    this.length--;
    return true;
  }

  reverse() {
    // Swap the head and tail
    // Create a variable called next
    // Create a variable called prev
    // Create a variable called node and initialize it to the head property
    // Loop through the list
    // See the next to be the next property on whatever node is
    // Set thee next property on the node to be whatever prev is
    // Set prev to be the value of the node variable
    // Set the node variable to be the value of the next variable

    let node = this.head;
    this.head = this.tail;
    this.tail = node;

    let next;
    let prev = null;
    for (let i = 0; i < this.length; i++) {
      next = node.next;
      node.next = prev;
      prev = node;
      node = next;
    }
    return this;
  }
}

var list = new SingleLinkedList();
list.push('Hi');
list.push('there');
list.push('!');
list.unshift('Yo');

console.log(list.set(0, 'Yo Bro'));

console.log('-- list:', list);
list.insert(0, 'Wassup');
console.log('--- list:', list);
list.insert(5, '๐Ÿ’“');
console.log('--- list', list);
list.insert(1, 'โค๏ธ');
console.log('--- list', list);

list.remove(7);
console.log('--- list', list);
list.remove(0);
console.log('--- list', list);
list.remove(1);
console.log('--- list', list);

๋ฐฐ์—ด(Array)์™€์˜ ์ฐจ์ด์ 

  1. ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๋ฐฉ์‹:
    • ๋ฐฐ์—ด: ์—ฐ์†๋œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ์š”์†Œ๋“ค์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ: ์š”์†Œ๋“ค์ด ๋ถˆ์—ฐ์†์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์š”์†Œ๋Š” ํฌ์ธํ„ฐ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
  2. ์ ‘๊ทผ ์‹œ๊ฐ„:
    • ๋ฐฐ์—ด: ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด O(1) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ์ž„์˜์˜ ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ: ํŠน์ • ์š”์†Œ์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ถ€ํ„ฐ ์ˆœ์ฐจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํ‰๊ท ์ ์œผ๋กœ O(n) ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.
  3. ์‚ฝ์ž… ๋ฐ ์‚ญ์ œ:
    • ๋ฐฐ์—ด: ํŠน์ • ์œ„์น˜์— ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋ ค๋ฉด ์š”์†Œ๋“ค์„ ์ด๋™ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ํ‰๊ท ์ ์œผ๋กœ O(n) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
    • ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ: ํŠน์ • ์œ„์น˜์— ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ ์š”์†Œ๋“ค์„ ์ด๋™ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๋Š” O(1) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹จ, ์‚ฝ์ž… ๋˜๋Š” ์‚ญ์ œํ•  ์œ„์น˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด O(n) ์‹œ๊ฐ„์ด ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  4. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ:
    • ๋ฐฐ์—ด: ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ: ๊ฐ ์š”์†Œ๋งˆ๋‹ค ์ถ”๊ฐ€์ ์ธ ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ, ๋ฐฐ์—ด๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋งŽ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. ์—ฐ๊ฒฐ์„ฑ:
    • ๋ฐฐ์—ด: ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ, ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ํ• ๋‹นํ•˜๊ณ  ๊ธฐ์กด ์š”์†Œ๋“ค์„ ๋ณต์‚ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ: ๋™์ ์œผ๋กœ ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ์ƒ๋Œ€์ ์œผ๋กœ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์™€ ๋ฐฐ์—ด์€ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์žฅ์ ๊ณผ ๋‹จ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์‚ฌ์šฉ ๋ชฉ์ ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์€ ๋น ๋ฅธ ์ ‘๊ทผ ์‹œ๊ฐ„์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์ ํ•ฉํ•˜๊ณ , ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ๋นˆ๋ฒˆํ•œ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Double Linked List

๋”๋ธ” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ(Doubly Linked List)๋Š” ๊ฐ ๋…ธ๋“œ๊ฐ€ ๋‘ ๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง€๋Š” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ , ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ด์ „ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธ์˜ ์–‘๋ฐฉํ–ฅ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

์ฃผ์š” ํŠน์ง•

  1. ๋…ธ๋“œ ๊ตฌ์กฐ(Node Structure): ๊ฐ ๋…ธ๋“œ๋Š” data, next, prev ์„ธ ๊ฐ€์ง€ ์†์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
    • data: ๋…ธ๋“œ๊ฐ€ ์ €์žฅํ•˜๋Š” ๋ฐ์ดํ„ฐ
    • next: ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
    • prev: ์ด์ „ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
  2. ๋ฆฌ์ŠคํŠธ์˜ ๊ตฌ์กฐ(List Structure): ๋”๋ธ” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” head์™€ tail ๋‘ ๊ฐœ์˜ ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
    • head: ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
    • tail: ๋ฆฌ์ŠคํŠธ์˜ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
  3. ์–‘๋ฐฉํ–ฅ ํƒ์ƒ‰: ์–‘๋ฐฉํ–ฅ์œผ๋กœ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜์—ฌ, ์•ž๋’ค๋กœ ์ด๋™ํ•˜๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ์—ฐ์‚ฐ

  1. ์ถ”๊ฐ€ (Insertion):
    • ๋ฆฌ์ŠคํŠธ์˜ ์•ž์— ์ถ”๊ฐ€: unshift
    • ๋ฆฌ์ŠคํŠธ์˜ ๋์— ์ถ”๊ฐ€: push
    • ๋ฆฌ์ŠคํŠธ์˜ ์ค‘๊ฐ„์— ์ถ”๊ฐ€: insert
  2. ์ œ๊ฑฐ (Removal):
    • ๋ฆฌ์ŠคํŠธ์˜ ์•ž์—์„œ ์ œ๊ฑฐ: shift
    • ๋ฆฌ์ŠคํŠธ์˜ ๋์—์„œ ์ œ๊ฑฐ: pop
    • ๋ฆฌ์ŠคํŠธ์˜ ์ค‘๊ฐ„์—์„œ ์ œ๊ฑฐ: remove
  3. ํƒ์ƒ‰ (Traversal):
    • ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•œ ๋…ธ๋“œ ํƒ์ƒ‰: get

JavaScript๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

๋‹ค์Œ์€ ๋”๋ธ” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„์ž…๋‹ˆ๋‹ค.

class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
    this.prev = null;
  }
}

class DoubleLinkedList {
  constructor() {
    this.length = 0;
    this.head = null;
    this.tail = null;
  }

  push(data) {
    // Create a new node with the value passed to the function
    // If the head property is null set the head and tail to be the newly created node
    // If not, set the next property on the tail to be that node
    // Set the previous property on the newly created node to be the tail
    // Set the tail to be the newly created node
    // Increment the length
    // Return the Doubly Linked List

    let newNode = new Node(data);

    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      let currentTail = this.tail;

      this.tail.next = newNode;
      this.tail = newNode;
      this.tail.prev = currentTail;
    }

    this.length++;

    return this;
  }

  pop() {
    // If there is no head, return undefined
    // Store the current tail in a variable to return later
    // If the length is 1, set the head and tail to be null
    // Update the tail to be previous Node
    // Set the newTail's next to null
    // Decrement the length
    // Return the value removed

    if (!this.head || this.length <= 0) return undefined;
    let currentTail = this.tail;

    if (this.length === 1) {
      this.head = null;
      this.tail = null;
    } else {
      currentTail.prev.next = null;
      this.tail = currentTail.prev;
      currentTail.prev = null;
    }

    this.length--;
    return currentTail;
  }

  shift() {
    // If length is 0, return undefined
    // Store the current head property in a variable(we'll call it old head)
    // If the length is one > set the head to be null, set the tail to be null
    // Update the head to be the next of the old head
    // Set the head's prev property to null
    // Set the old head's next to null
    // Decrement the length
    // Return old head

    if (this.length === 0) return undefined;
    let currentHead = this.head;

    if (this.length === 1) {
      this.head = null;
      this.tail = null;
    } else {
      let newHead = this.head.next;

      newHead.prev = null;
      currentHead.next = null;

      this.head = newHead;
    }

    this.length--;
    return currentHead;
  }
  unshift(data) {
    // Create a new node with the value passed to the function
    // If the length is 0, Set the head to be the new node and Set the tail to be the new node
    // Other wise
    // Set the prev property on the head of the list to be the new node
    // Set the next property on the new node to be the head property
    // Update the head to be the new node
    // Increment the length
    // Return the list
    let newNode = new Node(data);

    if (this.length === 0) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      newNode.next = this.head;
      newNode.next.prev = newNode;

      this.head = newNode;
    }

    this.length++;
    return this;
  }

  traverse() {
    var current = this.head;
    while (current) {
      console.log('current:', current);
      current = current.next;
    }
  }

  get(index) {
    // If the index is less than 0 or greater or equal to the length, return null
    // If the index is less than or equal to half the length of the list
    // Loop through the list starting from the head and loop towards the middle
    // If the index is greater than half the length of the list
    // Loop through the list starting from the tail and loop towards the middle

    if (index < 0 || index >= this.length) return null;

    let cnt = 0;
    let currentValue = this.head;

    if (index <= Math.floor(this.length / 2)) {
      // from head to tail
      while (cnt !== index) {
        currentValue = currentValue.next;
        cnt++;
      }
    } else {
      // from tail to head
      cnt = this.length - 1;
      currentValue = this.tail;

      while (cnt !== index) {
        currentValue = currentValue.prev;
        cnt--;
      }
    }

    return currentValue;
  }

  set(index, data) {
    // Create a variable which is the result of the 'get' method at the index passed to the function
    // If the get method returns a valid node, set the value of that node to be the value passed to the function
    // Return true

    let currentNode = this.get(index);

    if (currentNode.data) {
      currentNode.data = data;
      return true;
    }

    return false;
  }

  insert(index, data) {
    // If the index is less than zero or greater than or equal to the length, return false
    // If the index is 0, unshift
    // If the index is the same as the length, push
    // Use get method to access the index -1
    // Set the next and prev properties on the correct nodes to link everything together
    if (index < 0 || index > this.length) return false;

    let newNode = new Node(data);

    if (index === 0) {
      this.unshift(newNode);
    } else if (index === this.length) {
      this.push(newNode);
    } else {
      let prevNode = this.get(index - 1);

      newNode.prev = prevNode;
      newNode.next = prevNode.next;
      prevNode.next = newNode;
      prevNode.next.next.prev = newNode;
    }
    this.length++;

    return newNode;
  }

  remove(index) {
    // If the index is less than zero or greater than or equal to the length return undefined
    // If the index is 0, shift
    // If the index is the same as the length-1, pop
    // Use the get method to retrieve the item to be removed
    // Update the next and prev properties to remove the found node from the list
    // Set next and prev to null on the found node
    // Decrement the length;
    // Return the removed node
    if (index < 0 || index > this.length) return false;

    if (index === 0) {
      this.shift();
    } else if (index === this.length - 1) {
      this.pop();
    } else {
      let currentNode = this.get(index);
      let prevNode = currentNode.prev;

      prevNode.next.next.prev = currentNode.prev;
      prevNode.next = currentNode.next;

      currentNode.prev = null;
      currentNode.next = null;

      this.length--;
      return currentNode;
    }
  }
}

Array์™€์˜ ์ฐจ์ด์ 

  1. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ: ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ๋…ธ๋“œ๋‹น ์ถ”๊ฐ€์ ์ธ ํฌ์ธํ„ฐ(next, prev)๋ฅผ ์ €์žฅํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ๋ฐฐ์—ด๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค.
  2. ์ ‘๊ทผ ์‹œ๊ฐ„: ๋ฐฐ์—ด์€ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด O(1) ์‹œ๊ฐ„์— ์š”์†Œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” O(n) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
  3. ์‚ฝ์ž…/์‚ญ์ œ ์‹œ๊ฐ„: ๋ฐฐ์—ด์€ ์ค‘๊ฐ„์— ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ๋•Œ O(n) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ์ง€๋งŒ, ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ํ•ด๋‹น ์œ„์น˜๋ฅผ ์ฐพ๋Š” ์‹œ๊ฐ„(O(n)) ์™ธ์—๋Š” O(1) ์‹œ๊ฐ„์— ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋”๋ธ” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” ์–‘๋ฐฉํ–ฅ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์–ด, ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๊ฐ€ ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐฐ์—ด์— ๋น„ํ•ด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋งŽ๊ณ , ์ž„์˜ ์ ‘๊ทผ์ด ๋Š๋ฆฌ๋‹ค๋Š” ๋‹จ์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Stack

์Šคํƒ(Stack)์€ ํ›„์ž…์„ ์ถœ(LIFO, Last In First Out) ์›์น™์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋งˆ์ง€๋ง‰์— ์‚ฝ์ž…๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ์ œ๊ฑฐ๋˜๋Š” ๊ตฌ์กฐ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์Šคํƒ์€ ์ฃผ๋กœ ์žฌ๊ท€ ์•Œ๊ณ ๋ฆฌ์ฆ˜, ์–ธ์–ด์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ, ์‹คํ–‰ ์ทจ์†Œ ๊ธฐ๋Šฅ ๋“ฑ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ์—ฐ์‚ฐ

  1. push: ์Šคํƒ์˜ ๋งจ ์œ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. pop: ์Šคํƒ์˜ ๋งจ ์œ„์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. peek (๋˜๋Š” top): ์Šคํƒ์˜ ๋งจ ์œ„์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
  4. isEmpty: ์Šคํƒ์ด ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  5. size: ์Šคํƒ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์Šคํƒ์˜ ํŠน์ง•

  • LIFO: ๋งˆ์ง€๋ง‰์— ์‚ฝ์ž…๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.
  • ์ œํ•œ๋œ ์ ‘๊ทผ: ์Šคํƒ์€ ์˜ค์ง ํ•œ์ชฝ ๋์—์„œ๋งŒ ๋ฐ์ดํ„ฐ์˜ ์‚ฝ์ž…๊ณผ ์ œ๊ฑฐ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์Šคํƒ์˜ ํ™œ์šฉ ์˜ˆ์‹œ

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

JavaScript๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

๋‹ค์Œ์€ JavaScript๋กœ ์Šคํƒ์„ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class Stack {
  constructor() {
    this.top = null; // ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ
    this.size = 0; // ์Šคํƒ์˜ ํฌ๊ธฐ
  }

  // ์Šคํƒ์— ์š”์†Œ ์ถ”๊ฐ€
  push(value) {
    const newNode = new Node(value);
    if (!this.top) {
      this.top = newNode;
    } else {
      newNode.next = this.top;
      this.top = newNode;
    }
    this.size++;
    return this;
  }

  // ์Šคํƒ์—์„œ ์š”์†Œ ์ œ๊ฑฐ ๋ฐ ๋ฐ˜ํ™˜
  pop() {
    if (!this.top) return null;
    const removedNode = this.top;
    this.top = this.top.next;
    this.size--;
    return removedNode.value;
  }

  // ์Šคํƒ์˜ ๋งจ ์œ„ ์š”์†Œ ๋ฐ˜ํ™˜ (์ œ๊ฑฐํ•˜์ง€ ์•Š์Œ)
  peek() {
    if (!this.top) return null;
    return this.top.value;
  }

  // ์Šคํƒ์ด ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
  isEmpty() {
    return this.size === 0;
  }

  // ์Šคํƒ์˜ ํฌ๊ธฐ ๋ฐ˜ํ™˜
  getSize() {
    return this.size;
  }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
const stack = new Stack();
stack.push(10);
stack.push(20);
stack.push(30);

console.log(stack.peek()); // 30
console.log(stack.pop()); // 30
console.log(stack.getSize()); // 2
console.log(stack.isEmpty()); // false
console.log(stack.pop()); // 20
console.log(stack.pop()); // 10
console.log(stack.isEmpty()); // true

๋ฐฐ์—ด๊ณผ์˜ ์ฐจ์ด์ 

  1. ์ ‘๊ทผ ๋ฐฉ์‹: ์Šคํƒ์€ LIFO ๊ตฌ์กฐ๋กœ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐ˜๋ฉด, ๋ฐฐ์—ด์€ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ์ž„์˜ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  2. ์—ฐ์‚ฐ ์‹œ๊ฐ„ ๋ณต์žก๋„: ์Šคํƒ์˜ push์™€ pop ์—ฐ์‚ฐ์€ O(1) ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋ฐฐ์—ด์—์„œ๋„ ๋์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์€ O(1)์ด์ง€๋งŒ, ๋ฐฐ์—ด์˜ ์ค‘๊ฐ„์— ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์€ O(n)์ž…๋‹ˆ๋‹ค.

์Šคํƒ์€ ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์žฌ๊ท€์  ๋ฌธ์ œ ํ•ด๊ฒฐ, ์‹คํ–‰ ์ทจ์†Œ ๊ธฐ๋Šฅ, ํ•จ์ˆ˜ ํ˜ธ์ถœ ๊ด€๋ฆฌ ๋“ฑ์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Queue

ํ(Queue)๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์˜ ํ•œ ํ˜•ํƒœ๋กœ, ์„ ์ž…์„ ์ถœ(FIFO, First In First Out) ์›์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์ฆ‰, ๋จผ์ € ์‚ฝ์ž…๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋จผ์ € ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค. ํ๋Š” ์ผ์ƒ ์ƒํ™œ์˜ ์ค„ ์„œ๊ธฐ์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ๋žŒ๋“ค์ด ์ค„์„ ์„œ์„œ ๋Œ€๊ธฐํ•˜๋Š” ๊ฒฝ์šฐ, ์ค„์˜ ๋งจ ์•ž์— ์žˆ๋Š” ์‚ฌ๋žŒ์ด ๊ฐ€์žฅ ๋จผ์ € ์„œ๋น„์Šค๋ฐ›๊ณ  ์ค„์—์„œ ๋‚˜๊ฐ€๋ฉฐ, ์ƒˆ๋กœ์šด ์‚ฌ๋žŒ์€ ์ค„์˜ ๋งจ ๋’ค์— ์„œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ์˜ ๊ธฐ๋ณธ ์—ฐ์‚ฐ

  1. enqueue: ํ์˜ ๋งจ ๋’ค์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. dequeue: ํ์˜ ๋งจ ์•ž์—์„œ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. peek/front: ํ์˜ ๋งจ ์•ž ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ, ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
  4. isEmpty: ํ๊ฐ€ ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  5. size: ํ์˜ ์š”์†Œ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ํ์˜ ํ™œ์šฉ ์‚ฌ๋ก€

  • ์šด์˜ ์ฒด์ œ: ์ž‘์—… ์Šค์ผ€์ค„๋ง ๋ฐ ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ํ”„๋ฆฐํ„ฐ ๊ด€๋ฆฌ: ์ธ์‡„ ๋Œ€๊ธฐ์—ด์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ๋„คํŠธ์›Œํฌ: ๋ฐ์ดํ„ฐ ํŒจํ‚ท์˜ ์ „์†ก ์ˆœ์„œ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์ฝœ ์„ผํ„ฐ ๋Œ€๊ธฐ์—ด: ๊ณ ๊ฐ ์„œ๋น„์Šค์—์„œ ์ฝœ ๋Œ€๊ธฐ์—ด ๊ด€๋ฆฌ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ์˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

ํ๋Š” ๋ฐฐ์—ด์ด๋‚˜ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„์€ ๊ณ ์ •๋œ ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„์€ ๋™์  ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

๋ฐฐ์—ด ๊ธฐ๋ฐ˜ ๊ตฌํ˜„

๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ ํ๋Š” ์ •์  ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ๋•Œ๋งˆ๋‹ค ๋ฐฐ์—ด์„ ์ด๋™์‹œํ‚ค๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

class ArrayQueue {
  constructor() {
    this.queue = [];
  }

  enqueue(value) {
    this.queue.push(value);
  }

  dequeue() {
    return this.queue.shift();
  }

  peek() {
    return this.queue[0];
  }

  isEmpty() {
    return this.queue.length === 0;
  }

  size() {
    return this.queue.length;
  }
}

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ ๊ธฐ๋ฐ˜ ๊ตฌํ˜„

๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ํ๋Š” ๋™์  ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ๋•Œ ํฌ์ธํ„ฐ๋ฅผ ์ด๋™์‹œํ‚ค๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class LinkedListQueue {
  constructor() {
    this.first = null; // ํ์˜ ๋งจ ์•ž ์š”์†Œ
    this.last = null; // ํ์˜ ๋งจ ๋’ค ์š”์†Œ
    this.size = 0; // ํ์˜ ํฌ๊ธฐ
  }

  enqueue(value) {
    const newNode = new Node(value);
    if (!this.first) {
      this.first = newNode;
      this.last = newNode;
    } else {
      this.last.next = newNode;
      this.last = newNode;
    }
    this.size++;
    return this;
  }

  dequeue() {
    if (!this.first) return null;
    const removedNode = this.first;
    if (this.first === this.last) {
      this.last = null;
    }
    this.first = this.first.next;
    this.size--;
    return removedNode.value;
  }

  peek() {
    if (!this.first) return null;
    return this.first.value;
  }

  isEmpty() {
    return this.size === 0;
  }

  getSize() {
    return this.size;
  }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
const queue = new LinkedListQueue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);

console.log(queue.peek()); // 10
console.log(queue.dequeue()); // 10
console.log(queue.getSize()); // 2
console.log(queue.isEmpty()); // false
console.log(queue.dequeue()); // 20
console.log(queue.dequeue()); // 30
console.log(queue.isEmpty()); // true

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„๋œ ํ๋Š” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์  ํฌ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์š”์†Œ์˜ ์ถ”๊ฐ€์™€ ์ œ๊ฑฐ๊ฐ€ O(1) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์ด๋Š” ํ์˜ ํšจ์œจ์ ์ธ ๋™์ž‘์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

Binary Search Tree

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ(Binary Search Tree, BST)๋Š” ๋ฐ์ดํ„ฐ์˜ ํšจ์œจ์ ์ธ ์ €์žฅ, ๊ฒ€์ƒ‰, ์‚ฝ์ž… ๋ฐ ์‚ญ์ œ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ํŠธ๋ฆฌ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ๊ฐ ๋…ธ๋“œ๊ฐ€ ์ตœ๋Œ€ ๋‘ ๊ฐœ์˜ ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’์€ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ์ž‘๊ณ , ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’์€ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์„ฑ ๋•๋ถ„์— ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋Š” ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ํŠน์„ฑ

  1. ๋ชจ๋“  ๋…ธ๋“œ์˜ ๊ฐ’์€ ์œ ์ผํ•ฉ๋‹ˆ๋‹ค.
  2. ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๋…ธ๋“œ ๊ฐ’์€ ๋ถ€๋ชจ ๋…ธ๋“œ ๊ฐ’๋ณด๋‹ค ์ž‘์Šต๋‹ˆ๋‹ค.
  3. ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋ชจ๋“  ๋…ธ๋“œ ๊ฐ’์€ ๋ถ€๋ชจ ๋…ธ๋“œ ๊ฐ’๋ณด๋‹ค ํฝ๋‹ˆ๋‹ค.
  4. ์™ผ์ชฝ ๋ฐ ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ๋„ ๊ฐ๊ฐ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค.

์ฃผ์š” ์—ฐ์‚ฐ

  1. ์‚ฝ์ž… (Insert): ์ƒˆ๋กœ์šด ๊ฐ’์„ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฒ€์ƒ‰ (Search): ํŠน์ • ๊ฐ’์ด ํŠธ๋ฆฌ์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์˜ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(value) {
    // Create a new node
    // Starting at the root
    // Check if there is a root, if not - the root now becomes that new node
    // If there is a root, check if the value of the new node is greater than or less than the value of the root

    // If it is greater
    // Check to see if there is a node to the right
    // If there is, move to that node and repeat these steps
    // If there is not, add that node as the right property

    // If it is less
    // Check to see if there a node to the left
    // If there is, move to that node and repeat these steps
    // If there is not, add that node as the left property
    let newNode = new Node(value);

    if (!this.root) {
      this.root = newNode;
      return this;
    }

    let current = this.root;

    while (true) {
      if (value === current.value) return undefined;

      if (value < current.value) {
        if (current.left === null) {
          current.left = newNode;
          return this;
        }
        current = current.left;
      } else if (value > current.value) {
        if (current.right === null) {
          current.right = newNode;
          return this;
        }
        current = current.right;
      }
    }
  }

  search(value) {
    // Starting at the root
    // Check if there is a root, if not - we're done searching!
    // If there is a root, check if the value of the new node is the value we are looking for.
    // If we found it, we're done!
    // If not, check to see if the value is greater than or less than the value of the root
    // If it is greater
    // Check to see if there is a node to the right
    // If there is, move to that node and repeat these steps
    // If there is not, we're done searching
    // If it is less
    // Check to see if there is a node to the left
    // If there is, move to that node and repeat these steps
    // If there is not, we're done searching!

    if (!this.root) return false;

    let current = this.root;
    let found = false;

    while (current && !found) {
      if (value < current.value) {
        current = current.left;
      } else if (value > current.value) {
        current = current.right;
      } else {
        return true;
      }
    }

    return false;
  }
}

let tree = new BinarySearchTree();

console.log('tree is:', tree);
tree.insert(10);
tree.insert(5);
tree.insert(15);
tree.insert(17);
tree.insert(7);
tree.insert(3);
tree.insert(13);
console.log('tree is:', tree);

console.log(tree.search(13));
console.log(tree.search(19));

์„ค๋ช…

  1. Node ํด๋ž˜์Šค:
    • value: ๋…ธ๋“œ์˜ ๊ฐ’.
    • left: ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ.
    • right: ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ.
  2. BinarySearchTree ํด๋ž˜์Šค:
    • root: ํŠธ๋ฆฌ์˜ ๋ฃจํŠธ ๋…ธ๋“œ.
  3. insert(value):
    • ์ƒˆ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ ๋…ธ๋“œ๋ฅผ ๋ฃจํŠธ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ๊ฐ’์„ ๋น„๊ตํ•˜์—ฌ ์™ผ์ชฝ ๋˜๋Š” ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ๋กœ ์ด๋™ํ•˜๋ฉด์„œ ์‚ฝ์ž… ์œ„์น˜๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
  4. search(value):
    • ํŠธ๋ฆฌ์—์„œ ํŠน์ • ๊ฐ’์„ ๊ฐ€์ง„ ๋…ธ๋“œ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.
    • ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ๊ฐ’์„ ๋น„๊ตํ•˜๋ฉด์„œ ์™ผ์ชฝ ๋˜๋Š” ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋Š” ์‚ฝ์ž…, ์‚ญ์ œ, ๊ฒ€์ƒ‰ ์—ฐ์‚ฐ์ด ํ‰๊ท ์ ์œผ๋กœ O(log n) ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ตœ์•…์˜ ๊ฒฝ์šฐ(ํŽธํ–ฅ ํŠธ๋ฆฌ)์—๋Š” O(n) ์‹œ๊ฐ„ ๋ณต์žก๋„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๊ท ํ˜• ์žกํžŒ ํŠธ๋ฆฌ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด AVL ํŠธ๋ฆฌ, ๋ ˆ๋“œ-๋ธ”๋ž™ ํŠธ๋ฆฌ์™€ ๊ฐ™์€ ๋ณ€ํ˜• ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Breadth First Search

๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰(Breadth-First Search, BFS)์€ ๊ทธ๋ž˜ํ”„ ๋˜๋Š” ํŠธ๋ฆฌ์˜ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. BFS๋Š” ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ์ถœ๋ฐœํ•˜์—ฌ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋ฅผ ๋จผ์ € ํƒ์ƒ‰ํ•˜๊ณ , ๊ทธ ๋‹ค์Œ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋“ค์˜ ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ฃผ๋กœ ํ(queue) ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค.

BFS์˜ ํŠน์ง•

  1. ๋ ˆ๋ฒจ๋ณ„ ํƒ์ƒ‰: BFS๋Š” ํŠธ๋ฆฌ ๋˜๋Š” ๊ทธ๋ž˜ํ”„์˜ ๋ ˆ๋ฒจ์„ ๊ธฐ์ค€์œผ๋กœ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ฒซ ๋ฒˆ์งธ ๋ ˆ๋ฒจ(๋ฃจํŠธ ๋…ธ๋“œ)์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๋‹ค์Œ ๋ ˆ๋ฒจ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ตœ๋‹จ ๊ฒฝ๋กœ ํƒ์ƒ‰: ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ BFS๋Š” ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ๋‹ค๋ฅธ ๋…ธ๋“œ๋กœ ๊ฐ€๋Š” ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ํ ์‚ฌ์šฉ: BFS๋Š” FIFO(First In, First Out) ํŠน์„ฑ์„ ๊ฐ€์ง„ ํ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ์— ํƒ์ƒ‰ํ•  ๋…ธ๋“œ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

BFS์˜ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

ํŠธ๋ฆฌ์™€ ๊ทธ๋ž˜ํ”„๋ฅผ ์œ„ํ•œ BFS์˜ ๊ตฌํ˜„ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํŠธ๋ฆฌ์—์„œ์˜ BFS ๊ตฌํ˜„

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(value) {
    let newNode = new Node(value);

    if (!this.root) {
      this.root = newNode;
      return this;
    }

    let current = this.root;

    while (true) {
      if (value === current.value) return undefined;

      if (value < current.value) {
        if (current.left === null) {
          current.left = newNode;
          return this;
        }
        current = current.left;
      } else if (value > current.value) {
        if (current.right === null) {
          current.right = newNode;
          return this;
        }
        current = current.right;
      }
    }
  }

  find(value) {
    if (!this.root) return false;

    let current = this.root;
    let found = false;

    while (current && !found) {
      if (value < current.value) {
        current = current.left;
      } else if (value > current.value) {
        current = current.right;
      } else {
        return true;
      }
    }

    return false;
  }

  BFS() {
    // Create a queue (this can be an array) and a variable to store the values of nodes visited
    // Place the root node in the queue
    // Loop as long as there is anything in the queue
    // Dequeue a node from the queue and push the value of the node into the variable that stroes the nodes
    // If there is a left property on the node dequeud - add it to the queue
    // If there is a right property on the node dequeued - add it to the queue
    // Return the variable that stores the values

    let visited = [];
    let queue = [];
    let currentNode = this.root;

    queue.push(currentNode);

    while (queue.length) {
      currentNode = queue.shift();
      visited.push(currentNode.value);

      if (currentNode.left) queue.push(currentNode.left);
      if (currentNode.right) queue.push(currentNode.right);
    }
    return visited;
  }
}

let tree = new BinarySearchTree();

console.log('tree is:', tree);
tree.insert(10);
tree.insert(5);
tree.insert(15);
tree.insert(17);
tree.insert(7);
tree.insert(3);
tree.insert(13);
console.log('tree is:', tree);

console.log(tree.find(13));
console.log(tree.find(19));

console.log('BFS:', tree.BFS());

BFS์˜ ๋™์ž‘ ์›๋ฆฌ

  1. ํ ์ดˆ๊ธฐํ™”: ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ํ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ๊ฐ€ ๋นŒ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต:
    • ํ์—์„œ ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊บผ๋‚ด ํ˜„์žฌ ๋…ธ๋“œ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • ํ˜„์žฌ ๋…ธ๋“œ์˜ ๋ชจ๋“  ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ํ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(์ด๋ฏธ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋Š” ์ œ์™ธ).
  3. ๋ฐ˜๋ณต ์ข…๋ฃŒ: ํ๊ฐ€ ๋น„๋ฉด ํƒ์ƒ‰์ด ์™„๋ฃŒ๋˜๊ณ , ๊ฒฐ๊ณผ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

BFS์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

BFS์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๊ทธ๋ž˜ํ”„์˜ ๋…ธ๋“œ ์ˆ˜(V)์™€ ์—ฃ์ง€ ์ˆ˜(E)์— ๋”ฐ๋ผ O(V + E)์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  ๋…ธ๋“œ์™€ ์—ฃ์ง€๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ์˜ ๊ฒฝ์šฐ ๋…ธ๋“œ ์ˆ˜๊ฐ€ n์ผ ๋•Œ, ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(n)์ž…๋‹ˆ๋‹ค.

BFS๋Š” ๋„ˆ๋น„ ์šฐ์„ ์œผ๋กœ ํƒ์ƒ‰ํ•˜์—ฌ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š” ๋ฌธ์ œ์— ์ ํ•ฉํ•˜๋ฉฐ, ๋ชจ๋“  ๊ฒฝ๋กœ๋ฅผ ์™„์ „ํžˆ ํƒ์ƒ‰ํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Depth First Search

๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰(Depth-First Search, DFS)์€ ๊ทธ๋ž˜ํ”„ ๋˜๋Š” ํŠธ๋ฆฌ์˜ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ, ๊ฐ€๋Šฅํ•œ ํ•œ ๊นŠ์ด ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ์šฐ์„ ์œผ๋กœ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. DFS๋Š” ์Šคํƒ(stack) ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์žฌ๊ท€์ ์œผ๋กœ๋„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

DFS์˜ ํŠน์ง•

  1. ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰: ๊ฐ€๋Šฅํ•œ ํ•œ ๊นŠ์ด ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ๋จผ์ € ํƒ์ƒ‰ํ•˜๊ณ , ๋” ์ด์ƒ ๊นŠ์ด ๊ฐˆ ์ˆ˜ ์—†์„ ๋•Œ ๋‹ค์Œ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  2. ์Šคํƒ ์‚ฌ์šฉ: DFS๋Š” LIFO(Last In, First Out) ํŠน์„ฑ์„ ๊ฐ€์ง„ ์Šคํƒ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ์— ํƒ์ƒ‰ํ•  ๋…ธ๋“œ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์žฌ๊ท€์  ๊ตฌํ˜„์—์„œ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ ์Šคํƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  3. ๊ฒฝ๋กœ ํƒ์ƒ‰: ๊ทธ๋ž˜ํ”„๋‚˜ ํŠธ๋ฆฌ์—์„œ ๊ฒฝ๋กœ๋ฅผ ํƒ์ƒ‰ํ•  ๋•Œ ์œ ์šฉํ•˜๋ฉฐ, ๋ชจ๋“  ๊ฒฝ๋กœ๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ๋ฌธ์ œ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

DFS์˜ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

ํŠธ๋ฆฌ์—์„œ์˜ DFS ๊ตฌํ˜„ (์žฌ๊ท€ ์‚ฌ์šฉ)

class Node {
  constructor(value) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

class BinarySearchTree {
  constructor() {
    this.root = null;
  }

  insert(value) {
    let newNode = new Node(value);

    if (!this.root) {
      this.root = newNode;
      return this;
    }

    let current = this.root;

    while (true) {
      if (value === current.value) return undefined;

      if (value < current.value) {
        if (current.left === null) {
          current.left = newNode;
          return this;
        }
        current = current.left;
      } else if (value > current.value) {
        if (current.right === null) {
          current.right = newNode;
          return this;
        }
        current = current.right;
      }
    }
  }

  find(value) {
    if (!this.root) return false;

    let current = this.root;
    let found = false;

    while (current && !found) {
      if (value < current.value) {
        current = current.left;
      } else if (value > current.value) {
        current = current.right;
      } else {
        return true;
      }
    }

    return false;
  }

  DFS() {
    // Create a variable to store the values of nodes visited
    // Store the root of the BST in a variable called current
    // Write a helper function which accepts a node
    // Push the value of the node to the variable that stores the values
    // If the node has a left property, call the helper function with the left property on the node
    // If the node has a right property, call the helper function with the right property on the node
    // Invoke the helper function with the current variable
    // Return the array of values

    let visited = [];
    let currentNode = this.root;

    function preorder(node) {
      visited.push(node.value);

      if (node.left) preorder(node.left);
      if (node.right) preorder(node.right);
    }

    preorder(currentNode);

    return visited;
  }
}

let tree = new BinarySearchTree();

console.log('tree is:', tree);
tree.insert(10);
tree.insert(5);
tree.insert(15);
tree.insert(17);
tree.insert(7);
tree.insert(3);
tree.insert(13);
console.log('tree is:', tree);

console.log(tree.find(13));
console.log(tree.find(19));

console.log('DFS:', tree.DFS());

DFS์˜ ๋™์ž‘ ์›๋ฆฌ

  1. ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ์ถœ๋ฐœ: DFS๋Š” ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ์ถœ๋ฐœํ•˜์—ฌ ๊นŠ์ด ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ๋จผ์ € ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
  2. ์žฌ๊ท€์  ๋˜๋Š” ๋ฐ˜๋ณต์  ์ ‘๊ทผ: ์žฌ๊ท€์ ์œผ๋กœ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ๊นŠ์ด ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•˜๊ฑฐ๋‚˜, ์Šคํƒ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋…ธ๋“œ๋ฅผ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐฉ๋ฌธ ํ‘œ์‹œ: ๊ฐ ๋…ธ๋“œ๋Š” ๋ฐฉ๋ฌธ๋˜๋ฉด ๋ฐฉ๋ฌธ ํ‘œ์‹œ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.
  4. ๋ฐฑํŠธ๋ž˜ํ‚น: ๋” ์ด์ƒ ๊นŠ์ด ๊ฐˆ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, ์ด์ „ ๋…ธ๋“œ๋กœ ๋˜๋Œ์•„๊ฐ€์„œ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋ฅผ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

DFS์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

DFS์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๊ทธ๋ž˜ํ”„์˜ ๋…ธ๋“œ ์ˆ˜(V)์™€ ์—ฃ์ง€ ์ˆ˜(E)์— ๋”ฐ๋ผ O(V + E)์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  ๋…ธ๋“œ์™€ ์—ฃ์ง€๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ์˜ ๊ฒฝ์šฐ ๋…ธ๋“œ ์ˆ˜๊ฐ€ n์ผ ๋•Œ, ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(n)์ž…๋‹ˆ๋‹ค.

DFS๋Š” ๊ฒฝ๋กœ ํƒ์ƒ‰, ์‚ฌ์ดํด ํƒ์ง€, ๊ฐ•๋ ฅ ์—ฐ๊ฒฐ ์š”์†Œ ์ฐพ๊ธฐ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์— ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

Binary Heap

์ด์ง„ ํž™(Binary Heap)์€ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ(Complete Binary Tree)์˜ ์ผ์ข…์œผ๋กœ, ํž™ ์†์„ฑ์„ ๋งŒ์กฑํ•˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํž™ ์†์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ํ˜•ํƒœ๋กœ ๊ตฌ๋ถ„๋ฉ๋‹ˆ๋‹ค:

  1. ์ตœ๋Œ€ ํž™(Max Heap): ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์ด ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ตฌ์กฐ.
  2. ์ตœ์†Œ ํž™(Min Heap): ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์ด ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ตฌ์กฐ.

์ด์ง„ ํž™

์ด์ง„ ํž™์˜ ํŠน์ง•

  1. ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ: ์ด์ง„ ํž™์€ ํ•ญ์ƒ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋ชจ๋“  ๋ ˆ๋ฒจ์ด ์™„์ „ํžˆ ์ฑ„์›Œ์ ธ ์žˆ๊ณ , ๋งˆ์ง€๋ง‰ ๋ ˆ๋ฒจ์˜ ๊ฒฝ์šฐ ์™ผ์ชฝ๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ๋…ธ๋“œ๊ฐ€ ์ฑ„์›Œ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ํž™ ์†์„ฑ: ์ตœ๋Œ€ ํž™์—์„œ๋Š” ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์ด ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™๊ณ , ์ตœ์†Œ ํž™์—์„œ๋Š” ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์ด ์ž์‹ ๋…ธ๋“œ์˜ ๊ฐ’๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด์ง„ ํž™์˜ ๊ตฌํ˜„

์ด์ง„ ํž™์€ ์ฃผ๋กœ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ์™€ ์ž์‹ ๋…ธ๋“œ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ์ธ๋ฑ์Šค: Math.floor((i - 1) / 2)
  • ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ์ธ๋ฑ์Šค: 2 * i + 1
  • ์˜ค๋ฅธ์ชฝ ์ž์‹ ๋…ธ๋“œ์˜ ์ธ๋ฑ์Šค: 2 * i + 2

์ด์ง„ ํž™

์ด์ง„ ํž™

์ด์ง„ ํž™

์ด์ง„ ํž™

์ด์ง„ ํž™

์ตœ๋Œ€ ํž™์˜ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

class MaxBinaryHeap {
  constructor() {
    this.values = [];
  }

  insert(value) {
    // Push the value into the values property on the heap
    // Bubble the value up to its correct spot!
    this.values.push(value);
    this.bubbleUp();
  }

  bubbleUp() {
    // Create a variable called index which is the length of the values property - 1
    // Create a variable called parentIndex which is the floor of (index-1)/2
    // Keep looping as long as the values element at the parentIndex is less than the values element at the child index
    // Swap the value of the values element at the parentIndex with the value of the element property at the child index
    // Set the index to be th parentIndex, and start over!

    let idx = this.values.length - 1;
    const element = this.values[idx];

    while (idx > 0) {
      let parentIdx = Math.floor((idx - 1) / 2);
      let parentElement = this.values[parentIdx];

      if (element <= parentElement) break;

      this.values[parentIdx] = element;
      this.values[idx] = parentElement;
      idx = parentIdx;
    }
  }

  extractMax() {
    // Swap the first value in the values property with the last one
    // Pop from the values property, so you can return the value at the end
    // Have the new root "sink down" to the correct spot
    // Your parent index starts at 0 (the root)
    // Find the index of the left child: 2 * idx + 1
    // Find the index of the right child: 2 * idx + 2
    // If the left or right child is greater than the element > swap
    // If both left and right children are larger, swap with the largest child
    // The child index you swapped to now becomes the new parent index
    // Keep looping and swapping until neither child is larger than the element
    // Return the old root
    const max = this.values[0];
    const end = this.values.pop();
    if (this.values.length > 0) {
      this.values[0] = end;
      this.sinkDown();
    }
    return max;
  }

  sinkDown() {
    let idx = 0;
    const length = this.values.length;
    const element = this.values[0];
    while (true) {
      let leftChildIdx = 2 * idx + 1;
      let rightChildIdx = 2 * idx + 2;
      let leftChild, rightChild;
      let swap = null;

      if (leftChildIdx < length) {
        leftChild = this.values[leftChildIdx];
        if (leftChild > element) {
          swap = leftChildIdx;
        }
      }
      if (rightChildIdx < length) {
        rightChild = this.values[rightChildIdx];
        if (
          (swap === null && rightChild > element) ||
          (swap !== null && rightChild > leftChild)
        ) {
          swap = rightChildIdx;
        }
      }
      if (swap === null) break;
      this.values[idx] = this.values[swap];
      this.values[swap] = element;
      idx = swap;
    }
  }
}

let maxBinaryHeap = new MaxBinaryHeap();
maxBinaryHeap.insert(41);
maxBinaryHeap.insert(39);
maxBinaryHeap.insert(33);
maxBinaryHeap.insert(18);
maxBinaryHeap.insert(27);
maxBinaryHeap.insert(12);

maxBinaryHeap.insert(55);
// [41,39,33,18,27,12,55]
//  0  1  2  3  4  5  6

console.log('maxBinaryHeap:', maxBinaryHeap);

์ตœ์†Œ ํž™์˜ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

์ตœ์†Œ ํž™์€ ์ตœ๋Œ€ ํž™๊ณผ ๊ฑฐ์˜ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋˜์ง€๋งŒ, ํž™ ์†์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€๋ชจ์™€ ์ž์‹ ๋…ธ๋“œ์˜ ํฌ๊ธฐ ๋น„๊ต๊ฐ€ ๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค.

class MinBinaryHeap {
  constructor() {
    this.values = [];
  }

  insert(value) {
    // Push the value into the values property on the heap
    // Bubble the value up to its correct spot!
    this.values.push(value);
    this.bubbleUp();
  }

  bubbleUp() {
    // Create a variable called index which is the length of the values property - 1
    // Create a variable called parentIndex which is the floor of (index-1)/2
    // Keep looping as long as the values element at the parentIndex is less than the values element at the child index
    // Swap the value of the values element at the parentIndex with the value of the element property at the child index
    // Set the index to be th parentIndex, and start over!

    let idx = this.values.length - 1;
    const element = this.values[idx];

    while (idx > 0) {
      let parentIdx = Math.floor((idx - 1) / 2);
      let parentElement = this.values[parentIdx];

      if (element >= parentElement) break;

      this.values[parentIdx] = element;
      this.values[idx] = parentElement;
      idx = parentIdx;
    }
  }

  extractMax() {
    // Swap the first value in the values property with the last one
    // Pop from the values property, so you can return the value at the end
    // Have the new root "sink down" to the correct spot
    // Your parent index starts at 0 (the root)
    // Find the index of the left child: 2 * idx + 1
    // Find the index of the right child: 2 * idx + 2
    // If the left or right child is greater than the element > swap
    // If both left and right children are larger, swap with the largest child
    // The child index you swapped to now becomes the new parent index
    // Keep looping and swapping until neither child is larger than the element
    // Return the old root
    const max = this.values[0];
    const end = this.values.pop();
    if (this.values.length > 0) {
      this.values[0] = end;
      this.sinkDown();
    }
    return max;
  }

  sinkDown() {
    let idx = 0;
    const length = this.values.length;
    const element = this.values[0];
    while (true) {
      let leftChildIdx = 2 * idx + 1;
      let rightChildIdx = 2 * idx + 2;
      let leftChild, rightChild;
      let swap = null;

      if (leftChildIdx < length) {
        leftChild = this.values[leftChildIdx];
        if (leftChild < element) {
          swap = leftChildIdx;
        }
      }
      if (rightChildIdx < length) {
        rightChild = this.values[rightChildIdx];
        if (
          (swap === null && rightChild < element) ||
          (swap !== null && rightChild < leftChild)
        ) {
          swap = rightChildIdx;
        }
      }
      if (swap === null) break;
      this.values[idx] = this.values[swap];
      this.values[swap] = element;
      idx = swap;
    }
  }
}

let minBinaryHeap = new MinBinaryHeap();
minBinaryHeap.insert(41);
minBinaryHeap.insert(39);
minBinaryHeap.insert(33);
minBinaryHeap.insert(18);
minBinaryHeap.insert(27);
minBinaryHeap.insert(12);

minBinaryHeap.insert(55);
// [12, 27, 18, 41, 33, 39, 55]
//  0  1  2  3  4  5  6

console.log('minBinaryHeap:', minBinaryHeap);

์ด์ง„ ํž™์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

  • ์‚ฝ์ž… ๋ฐ ์‚ญ์ œ: O(log n) - ํž™์˜ ๋†’์ด๊ฐ€ log n์ด๊ธฐ ๋•Œ๋ฌธ์— ์‚ฝ์ž…๊ณผ ์‚ญ์ œ ๋ชจ๋‘ log n ์‹œ๊ฐ„์— ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ๊ฒ€์ƒ‰: O(n) - ํž™์—์„œ ํŠน์ • ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ํ™•์ธํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ง„ ํž™์€ ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ตœ์†Œ ํž™์€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ ์š”์†Œ๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ, ์ตœ๋Œ€ ํž™์€ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์š”์†Œ๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Priority Queue

์šฐ์„ ์ˆœ์œ„ ํ(Priority Queue)๋Š” ๊ฐ ์š”์†Œ๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๋Š” ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ, ์ผ๋ฐ˜์ ์ธ ํ์™€ ๋‹ฌ๋ฆฌ ์š”์†Œ๋“ค์ด ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. ์šฐ์„ ์ˆœ์œ„ ํ๋Š” ํ์˜ ์ผ์ข…์ด์ง€๋งŒ, ์š”์†Œ๋ฅผ ์‚ฝ์ž…ํ•  ๋•Œ ๊ทธ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๊ณ , ์ œ๊ฑฐํ•  ๋•Œ๋Š” ๊ฐ€์žฅ ๋†’์€(๋˜๋Š” ๋‚ฎ์€) ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๋ฅผ ๋จผ์ € ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„ ์ˆœ์œ„ ํ์˜ ํŠน์ง•

  1. ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ฅธ ์š”์†Œ ๊ด€๋ฆฌ: ๊ฐ ์š”์†Œ๋Š” ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ํ์˜ ์š”์†Œ๋Š” ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค.
  2. ์‚ฝ์ž… ๋ฐ ์ œ๊ฑฐ: ์‚ฝ์ž… ์—ฐ์‚ฐ๊ณผ ์ œ๊ฑฐ ์—ฐ์‚ฐ์€ ๋ชจ๋‘ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.
  3. ์‘์šฉ ๋ถ„์•ผ: ์ž‘์—… ์Šค์ผ€์ค„๋ง, ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๊ด€๋ฆฌ, ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์‹œ์Šคํ…œ ๋“ฑ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๋ฐฉ๋ฒ•

์šฐ์„ ์ˆœ์œ„ ํ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์€ ํž™(heap) ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํž™์„ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฝ์ž…๊ณผ ์‚ญ์ œ ์—ฐ์‚ฐ์„ O(log n) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•œ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„

class PriorityQueue {
  constructor() {
    this.values = [];
  }

  enqueue(value, priority) {
    this.values.push({ value, priority });
    this.sort();
  }

  dequeue() {
    return this.values.shift();
  }

  sort() {
    this.values.sort((a, b) => a.priority - b.priority); // ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋‚ฎ์€ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ
  }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
let pq = new PriorityQueue();
pq.enqueue('low priority task', 5);
pq.enqueue('medium priority task', 3);
pq.enqueue('high priority task', 1);

console.log(pq.values); // [{value: "high priority task", priority: 1}, {value: "medium priority task", priority: 3}, {value: "low priority task", priority: 5}]
console.log(pq.dequeue()); // {value: "high priority task", priority: 1}

์œ„์˜ ๊ตฌํ˜„์€ ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์†Œ๋ฅผ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ์‹์€ ์ •๋ ฌํ•˜๋Š” ๋ฐ O(n log n)์˜ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฏ€๋กœ, ๋” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์€ ํž™์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํž™์„ ์‚ฌ์šฉํ•œ ์šฐ์„ ์ˆœ์œ„ ํ ๊ตฌํ˜„ (์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์˜ˆ์ œ)

  • ์ตœ์†Œ ํž™์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌํ˜„๋œ ์šฐ์„ ์ˆœ์œ„ ํ
  • ๊ธฐ์กด ์ด์ง„ ํž™์„ ๊ตฌํ˜„ํ•  ๋•Œ์™€์˜ ์ฐจ์ด์ ์€ priority ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค
class Node {
  constructor(value, priority) {
    this.value = value;
    this.priority = priority;
  }
}

class PriorityQueue {
  // Write a Min Binary Heap = lower number means higher priority
  // Each Node has a value and a priority. Use the priority to build the heap
  // Enqueue method accepts a value and priority, makes a new node, and puts it in the right spot based off its prioirty
  // Dequeue method removes root element, returns it, and rearranges heap using priority

  constructor() {
    this.values = [];
  }
  enqueue(val, priority) {
    let newNode = new Node(val, priority);
    this.values.push(newNode);
    this.bubbleUp();
  }
  bubbleUp() {
    let idx = this.values.length - 1;
    const element = this.values[idx];
    while (idx > 0) {
      let parentIdx = Math.floor((idx - 1) / 2);
      let parent = this.values[parentIdx];
      if (element.priority >= parent.priority) break;
      this.values[parentIdx] = element;
      this.values[idx] = parent;
      idx = parentIdx;
    }
  }
  dequeue() {
    const min = this.values[0];
    const end = this.values.pop();
    if (this.values.length > 0) {
      this.values[0] = end;
      this.sinkDown();
    }
    return min;
  }
  sinkDown() {
    let idx = 0;
    const length = this.values.length;
    const element = this.values[0];
    while (true) {
      let leftChildIdx = 2 * idx + 1;
      let rightChildIdx = 2 * idx + 2;
      let leftChild, rightChild;
      let swap = null;

      if (leftChildIdx < length) {
        leftChild = this.values[leftChildIdx];
        if (leftChild.priority < element.priority) {
          swap = leftChildIdx;
        }
      }
      if (rightChildIdx < length) {
        rightChild = this.values[rightChildIdx];
        if (
          (swap === null && rightChild.priority < element.priority) ||
          (swap !== null && rightChild.priority < leftChild.priority)
        ) {
          swap = rightChildIdx;
        }
      }
      if (swap === null) break;
      this.values[idx] = this.values[swap];
      this.values[swap] = element;
      idx = swap;
    }
  }
}

let ER = new PriorityQueue();

ER.enqueue('common cold', 5);
ER.enqueue('gunshot wound', 1);
ER.enqueue('high fever', 4);
ER.enqueue('broken arm', 2);
ER.enqueue('glass in foot', 3);

console.log('ER:', ER.dequeue());
console.log('ER:', ER.dequeue());
console.log('ER:', ER.dequeue());
console.log('ER:', ER.dequeue());
console.log('ER:', ER.dequeue());

์šฐ์„ ์ˆœ์œ„ ํ์˜ ์‘์šฉ

  1. ์ž‘์—… ์Šค์ผ€์ค„๋ง: ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ์ž‘์—…์„ ๋จผ์ € ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  2. ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜: ๊ทธ๋ž˜ํ”„์—์„œ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  3. ์ด๋ฒคํŠธ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ: ์ด๋ฒคํŠธ๋ฅผ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  4. ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๊ด€๋ฆฌ: ๋ฐ์ดํ„ฐ ํŒจํ‚ท์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•ด ์ „์†ก ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์šฐ์„ ์ˆœ์œ„ ํ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์œ ์šฉํ•œ ์ž๋ฃŒ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ, ํž™์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋ฉด ์‚ฝ์ž…๊ณผ ์‚ญ์ œ ์—ฐ์‚ฐ์„ ํšจ์œจ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ๋‹ค์–‘ํ•œ ์‘์šฉ ๋ถ„์•ผ์—์„œ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.

Hash Table

ํ•ด์‹œ ํ…Œ์ด๋ธ”(Hash Table)์€ ํ‚ค(Key)์™€ ๊ฐ’(Value)์˜ ์Œ์„ ์ €์žฅํ•˜๊ณ , ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค๋ฅผ ํ•ด์‹œ ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , ์ด๋ฅผ ์ธ๋ฑ์Šค๋กœ ์‚ฌ์šฉํ•ด ๋ฐฐ์—ด์— ๊ฐ’์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ํŠน์ง•

  1. ๋น ๋ฅธ ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ: ํ‰๊ท ์ ์œผ๋กœ O(1)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ํ•ด์‹œ ํ•จ์ˆ˜(Hash Function): ํ‚ค๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ํ•ด์‹œ ๊ฐ’(์ฃผ๋กœ ์ •์ˆ˜)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ข‹์€ ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ํ‚ค๋ฅผ ๊ณ ๋ฅด๊ฒŒ ๋ถ„ํฌ์‹œํ‚ค๊ณ  ์ถฉ๋Œ์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.
  3. ์ถฉ๋Œ(Collision): ์„œ๋กœ ๋‹ค๋ฅธ ํ‚ค๊ฐ€ ๋™์ผํ•œ ํ•ด์‹œ ๊ฐ’์„ ๊ฐ–๋Š” ์ƒํ™ฉ์„ ์ถฉ๋Œ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ฒด์ด๋‹(Chaining)๊ณผ ๊ฐœ๋ฐฉ ์ฃผ์†Œ๋ฒ•(Open Addressing)์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ถฉ๋Œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  1. ์ฒด์ด๋‹(Chaining): ๊ฐ ๋ฐฐ์—ด ์š”์†Œ๋ฅผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ, ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ๋ฆฌ์ŠคํŠธ์— ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  2. ๊ฐœ๋ฐฉ ์ฃผ์†Œ๋ฒ•(Open Addressing): ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ๋‹ค๋ฅธ ๋นˆ ์Šฌ๋กฏ์„ ์ฐพ์•„ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์„ ํ˜• ํƒ์‚ฌ(Linear Probing), ์ œ๊ณฑ ํƒ์‚ฌ(Quadratic Probing), ์ด์ค‘ ํ•ด์‹ฑ(Double Hashing) ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌํ˜„ํ•˜๊ธฐ

๊ฐ„๋‹จํ•œ ํ•ด์‹œ ํ•จ์ˆ˜ ๊ตฌํ˜„

function hash(key, arrayLen) {
  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) % arrayLen;
  }
  return total;
}

์ฒด์ด๋‹์„ ์ด์šฉํ•œ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๊ตฌํ˜„

class HashTable {
  // ์†Œ์ˆ˜ ๊ฐ’์„ ๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•œ๋‹ค
  constructor(size = 53) {
    this.keyMap = new Array(size);
  }

  _hash(key) {
    let total = 0;
    // ์†Œ์ˆ˜๋ฅผ ๊ณฑํ•˜๋ฉด, ๋‹จ์–ด๊ฐ„์˜ ์ถฉ๋Œ ํšŸ์ˆ˜๊ฐ€ ํ˜„์ €ํžˆ ์ค„์–ด๋“ค์—ˆ์Œ
    let WEIRD_PRIME = 31;

    // ํ‚ค ๊ฐ’์˜ ๊ธธ์ด๊ฐ€ 100์ด ๋„˜๋Š”๋‹ค๋ฉด, 100์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฃจํ”„๋ฅผ ๋ˆ๋‹ค
    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) {
    // Separate Chaining, Linear Probing ์ค‘ ๊ฐœ๋ณ„ ์ฒด์ด๋‹ ์‚ฌ์šฉ
    // Accepts a key and a value
    // Hashes the key
    // Stores the key-value pair in the hash table array via separate chaining
    let index = this._hash(key);

    if (!this.keyMap[index]) {
      this.keyMap[index] = [];
    }
    this.keyMap[index].push([key, value]);
  }

  get(key) {
    // Accepts a key
    // Hashes the key
    // Retrieves the key-value pair in the hash table
    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];
        }
      }
    }
    return undefined;
  }

  keys() {
    let results = [];
    for (let key of this.keyMap) {
      if (key) {
        for (let [key, value] of key) {
          if (!results.includes(key)) results.push(key);
        }
      }
    }
    return results;
  }

  values() {
    let results = [];
    for (let key of this.keyMap) {
      if (key) {
        for (let [key, value] of key) {
          if (!results.includes(value)) results.push(value);
        }
      }
    }
    return results;
  }
}

let newHashTable = new HashTable();

newHashTable.set('bowow', 'A');
newHashTable.set('cowow', 'B');
newHashTable.set('dowow', 'C');
newHashTable.set('Awwww', 'D');
newHashTable.set('Awwww', 'D');
newHashTable.set('Awwww', 'D');

newHashTable.get('Awwww');
console.log(newHashTable.keys());
console.log(newHashTable.values());

/**
 * newHashTable: HashTable {
  keyMap: [
    <19 empty items>,
    [ [Array] ],
    <3 empty items>,
    [ [Array], [Array] ],
    <3 empty items>,
    [ [Array] ],
    <25 empty items>
  ]
}
 */

์„ ํ˜• ํƒ์‚ฌ๋ฅผ ํ†ตํ•œ ๊ตฌํ˜„

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);
    // ์„ ํ˜• ํƒ์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋นˆ ์Šฌ๋กฏ์„ ์ฐพ์Œ
    while (this.keyMap[index] !== undefined && this.keyMap[index].key !== key) {
      index = (index + 1) % this.keyMap.length;
    }
    this.keyMap[index] = { key, value };
  }

  get(key) {
    let index = this._hash(key);
    // ์„ ํ˜• ํƒ์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค๋ฅผ ์ฐพ์Œ
    while (this.keyMap[index] !== undefined) {
      if (this.keyMap[index].key === key) {
        return this.keyMap[index].value;
      }
      index = (index + 1) % this.keyMap.length;
    }
    return undefined;
  }

  keys() {
    let keysArr = [];
    for (let i = 0; i < this.keyMap.length; i++) {
      if (this.keyMap[i]) {
        keysArr.push(this.keyMap[i].key);
      }
    }
    return keysArr;
  }

  values() {
    let valuesArr = [];
    for (let i = 0; i < this.keyMap.length; i++) {
      if (this.keyMap[i]) {
        valuesArr.push(this.keyMap[i].value);
      }
    }
    return valuesArr;
  }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
let ht = new HashTable(17);
ht.set('maroon', '#800000');
ht.set('yellow', '#FFFF00');
ht.set('olive', '#808000');
ht.set('salmon', '#FA8072');
ht.set('lightcoral', '#F08080');
ht.set('mediumvioletred', '#C71585');
ht.set('plum', '#DDA0DD');

console.log(ht.get('yellow')); // #FFFF00
console.log(ht.keys()); // ["maroon", "yellow", "olive", "salmon", "lightcoral", "mediumvioletred", "plum"]
console.log(ht.values()); // ["#800000", "#FFFF00", "#808000", "#FA8072", "#F08080", "#C71585", "#DDA0DD"]

ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ์žฅ์ 

  1. ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ: ํ‰๊ท ์ ์œผ๋กœ O(1) ์‹œ๊ฐ„ ๋ณต์žก๋„๋กœ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„: ๋น„๊ต์  ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์—์„œ ๋‚ด์žฅ ์ž๋ฃŒ ๊ตฌ์กฐ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ๋‹จ์ 

  1. ์ถฉ๋Œ ์ฒ˜๋ฆฌ: ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋ฉด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ณต๊ฐ„ ๋‚ญ๋น„: ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ •๋ ฌ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ: ๋ฐ์ดํ„ฐ๊ฐ€ ํŠน์ • ์ˆœ์„œ๋กœ ์ €์žฅ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ์‘์šฉ

  1. ์บ์‹ฑ: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์กฐํšŒ ๊ฒฐ๊ณผ ๋“ฑ์„ ์บ์‹ฑํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  2. ์ง‘ํ•ฉ ์—ฐ์‚ฐ: ์ง‘ํ•ฉ์˜ ํฌํ•จ ์—ฌ๋ถ€๋ฅผ ๋น ๋ฅด๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  3. ์—ฐ๊ด€ ๋ฐฐ์—ด: ํ‚ค์™€ ๊ฐ’์„ ๋งตํ•‘ํ•˜๋Š” ์—ฐ๊ด€ ๋ฐฐ์—ด์ด๋‚˜ ์‚ฌ์ „์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ๋งค์šฐ ๊ฐ•๋ ฅํ•˜๊ณ  ํšจ์œจ์ ์ธ ์ž๋ฃŒ ๊ตฌ์กฐ๋กœ, ๋งŽ์€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ์‹œ์Šคํ…œ์—์„œ ํ•„์ˆ˜์ ์ธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Graph

๊ทธ๋ž˜ํ”„(Graph)๋Š” ์ •์ (Vertex)๊ณผ ๊ฐ„์„ (Edge)์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ž๋ฃŒ ๊ตฌ์กฐ๋กœ, ์ •์  ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜ํ”„๋Š” ๋‹ค์–‘ํ•œ ํ˜•ํƒœ๋กœ ์กด์žฌํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜ํ”„์˜ ๊ธฐ๋ณธ ์šฉ์–ด

  1. ์ •์ (Vertex): ๊ทธ๋ž˜ํ”„์˜ ๋…ธ๋“œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ •์ ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ„์„ (Edge): ์ •์  ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ฐ„์„ ์€ ๋ฐฉํ–ฅ์ด ์žˆ์„ ์ˆ˜๋„(์œ ํ–ฅ ๊ทธ๋ž˜ํ”„) ์—†์„ ์ˆ˜๋„(๋ฌดํ–ฅ ๊ทธ๋ž˜ํ”„) ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ธ์ ‘ ์ •์ (Adjacent Vertex): ๊ฐ„์„ ์œผ๋กœ ์ง์ ‘ ์—ฐ๊ฒฐ๋œ ์ •์ ๋“ค์ž…๋‹ˆ๋‹ค.
  4. ๊ฒฝ๋กœ(Path): ํ•œ ์ •์ ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๋‹ค๋ฅธ ์ •์ ์œผ๋กœ ๊ฐ€๋Š” ์ผ๋ จ์˜ ๊ฐ„์„ ๋“ค์ž…๋‹ˆ๋‹ค.
  5. ๊ฐ€์ค‘์น˜(Weight): ๊ฐ„์„ ์— ๋ถ€์—ฌ๋œ ๊ฐ’์œผ๋กœ, ๋‘ ์ •์  ๊ฐ„์˜ ๋น„์šฉ์ด๋‚˜ ๊ฑฐ๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„๋ฅผ ๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„(Weighted Graph)๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜ํ”„์˜ ์ข…๋ฅ˜

  1. ๋ฌดํ–ฅ ๊ทธ๋ž˜ํ”„(Undirected Graph): ๊ฐ„์„ ์— ๋ฐฉํ–ฅ์ด ์—†๋Š” ๊ทธ๋ž˜ํ”„์ž…๋‹ˆ๋‹ค.
  2. ์œ ํ–ฅ ๊ทธ๋ž˜ํ”„(Directed Graph): ๊ฐ„์„ ์— ๋ฐฉํ–ฅ์ด ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์ž…๋‹ˆ๋‹ค.
  3. ๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„(Weighted Graph): ๊ฐ„์„ ์— ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์ž…๋‹ˆ๋‹ค.
  4. ๋น„๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„(Unweighted Graph): ๊ฐ„์„ ์— ๊ฐ€์ค‘์น˜๊ฐ€ ์—†๋Š” ๊ทธ๋ž˜ํ”„์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜ํ”„์˜ ํ‘œํ˜„ ๋ฐฉ๋ฒ•

  1. ์ธ์ ‘ ํ–‰๋ ฌ(Adjacency Matrix): ์ •์ ์„ ํ–‰๊ณผ ์—ด๋กœ ํ‘œํ˜„ํ•˜๊ณ , ์ •์  ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ํ–‰๋ ฌ์˜ ๊ฐ’์œผ๋กœ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉด 1, ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด 0์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์—์„œ๋Š” ๊ฐ€์ค‘์น˜๋ฅผ ํ–‰๋ ฌ์˜ ๊ฐ’์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  2. ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ(Adjacency List): ๊ฐ ์ •์ ์— ๋Œ€ํ•ด ์ธ์ ‘ํ•œ ์ •์ ๋“ค์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋Š” ๊ณต๊ฐ„ ํšจ์œจ์„ฑ์ด ์ข‹๊ณ , ๊ทธ๋ž˜ํ”„์˜ ์ •์ ๊ณผ ๊ฐ„์„ ์ด ๋งŽ์„ ๋•Œ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1. ์ธ์ ‘ ํ–‰๋ ฌ(Adjacency Matrix)

์ธ์ ‘ ํ–‰๋ ฌ

๊ฐœ๋…

์ธ์ ‘ ํ–‰๋ ฌ์€ ์ •์ ์„ ํ–‰๊ณผ ์—ด๋กœ ํ‘œ์‹œํ•˜๊ณ , ๋‘ ์ •์  ์‚ฌ์ด์— ๊ฐ„์„ ์ด ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ํ–‰๋ ฌ ์œ„์น˜์— 1(๋˜๋Š” ๊ฐ€์ค‘์น˜ ๊ฐ’)์„, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 0์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

  • ๊ณต๊ฐ„ ๋ณต์žก๋„: (O(V^2)) - (V)๋Š” ์ •์ ์˜ ์ˆ˜
  • ๊ฐ„์„  ์ถ”๊ฐ€: (O(1))
  • ๊ฐ„์„  ์‚ญ์ œ: (O(1))
  • ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ: (O(1))
  • ์ •์ ์˜ ๋ชจ๋“  ์ธ์ ‘ ์ •์  ํƒ์ƒ‰: (O(V))

์žฅ์ 

  1. ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ์ด ๋น ๋ฆ„: ํŠน์ • ๋‘ ์ •์  ์‚ฌ์ด์˜ ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ (O(1)) ์‹œ๊ฐ„์— ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ„์„  ์ถ”๊ฐ€/์‚ญ์ œ๊ฐ€ ๋น ๋ฆ„: (O(1)) ์‹œ๊ฐ„์— ๊ฐ„์„ ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ๊ณต๊ฐ„ ๋น„ํšจ์œจ์„ฑ: ์ •์ ์˜ ์ˆ˜๊ฐ€ ๋งŽ๊ณ  ๊ฐ„์„ ์˜ ์ˆ˜๊ฐ€ ์ ์€ ๊ฒฝ์šฐ(ํฌ์†Œ ๊ทธ๋ž˜ํ”„) ๋งŽ์€ ๊ณต๊ฐ„์ด ๋‚ญ๋น„๋ฉ๋‹ˆ๋‹ค.
  2. ์ •์ ์˜ ์ธ์ ‘ ์ •์  ํƒ์ƒ‰์ด ๋Š๋ฆผ: ํŠน์ • ์ •์ ์˜ ๋ชจ๋“  ์ธ์ ‘ ์ •์ ์„ ์ฐพ์œผ๋ ค๋ฉด ํ–‰๋ ฌ์˜ ํ•ด๋‹น ํ–‰ ์ „์ฒด๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ \(O(V)\) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.

2. ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ(Adjacency List)

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ 1

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ 2

๊ฐœ๋…

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋Š” ๊ฐ ์ •์ ์— ๋Œ€ํ•ด ์—ฐ๊ฒฐ๋œ ์ธ์ ‘ ์ •์ ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์ด๋‚˜ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

  • ๊ณต๊ฐ„ ๋ณต์žก๋„: (O(V + E)) - (E)๋Š” ๊ฐ„์„ ์˜ ์ˆ˜
  • ๊ฐ„์„  ์ถ”๊ฐ€: (O(1))
  • ๊ฐ„์„  ์‚ญ์ œ: (O(E / V)) ํ‰๊ท ์ ์œผ๋กœ, ์ตœ์•…์˜ ๊ฒฝ์šฐ (O(V))
  • ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ: (O(E / V)) ํ‰๊ท ์ ์œผ๋กœ, ์ตœ์•…์˜ ๊ฒฝ์šฐ (O(V))
  • ์ •์ ์˜ ๋ชจ๋“  ์ธ์ ‘ ์ •์  ํƒ์ƒ‰: (O(V)) ์ตœ์•…์˜ ๊ฒฝ์šฐ, ํ•˜์ง€๋งŒ ํ‰๊ท ์ ์œผ๋กœ ์ธ์ ‘ํ•œ ์ •์ ์˜ ์ˆ˜์— ๋น„๋ก€

์žฅ์ 

  1. ๊ณต๊ฐ„ ํšจ์œจ์„ฑ: ํฌ์†Œ ๊ทธ๋ž˜ํ”„์˜ ๊ฒฝ์šฐ ๊ณต๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ •์ ์˜ ์ธ์ ‘ ์ •์  ํƒ์ƒ‰์ด ๋น ๋ฆ„: ํŠน์ • ์ •์ ์˜ ๋ชจ๋“  ์ธ์ ‘ ์ •์ ์„ ๋น ๋ฅด๊ฒŒ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‰๊ท ์ ์œผ๋กœ ์ธ์ ‘ํ•œ ์ •์ ์˜ ์ˆ˜์— ๋น„๋ก€ํ•œ ์‹œ๊ฐ„์— ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ 

  1. ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ์ด ๋Š๋ฆผ: ํŠน์ • ๋‘ ์ •์  ์‚ฌ์ด์˜ ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ตœ์•…์˜ ๊ฒฝ์šฐ (O(V)) ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.
  2. ๊ฐ„์„  ์‚ญ์ œ๊ฐ€ ๋Š๋ฆผ: ๊ฐ„์„ ์„ ์‚ญ์ œํ•˜๋ ค๋ฉด ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์—์„œ ํ•ด๋‹น ๊ฐ„์„ ์„ ์ฐพ์•„์•ผ ํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„์ด ๋” ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ ํƒ ๊ธฐ์ค€

  1. ๊ทธ๋ž˜ํ”„์˜ ๋ฐ€๋„: ๊ทธ๋ž˜ํ”„๊ฐ€ ๋ฐ€์ง‘๋˜์–ด ์žˆ๊ณ  ๊ฐ„์„ ์˜ ์ˆ˜๊ฐ€ ์ •์ ์˜ ์ˆ˜์˜ ์ œ๊ณฑ์— ๋น„๋ก€ํ•œ๋‹ค๋ฉด ์ธ์ ‘ ํ–‰๋ ฌ์ด ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ, ํฌ์†Œ ๊ทธ๋ž˜ํ”„์—์„œ๋Š” ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ณต๊ฐ„ ํšจ์œจ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ: ๋‘ ์ •์  ์‚ฌ์ด์˜ ๊ฐ„์„  ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ๋นˆ๋ฒˆํ•˜๊ฒŒ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ธ์ ‘ ํ–‰๋ ฌ์ด ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
  3. ์ •์ ์˜ ์ธ์ ‘ ์ •์  ํƒ์ƒ‰: ํŠน์ • ์ •์ ์˜ ๋ชจ๋“  ์ธ์ ‘ ์ •์ ์„ ์ž์ฃผ ํƒ์ƒ‰ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋น„๊ต์™€ ์žฅ๋‹จ์ ์„ ๊ณ ๋ คํ•˜์—ฌ, ๊ทธ๋ž˜ํ”„์˜ ํŠน์„ฑ๊ณผ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์ ํ•ฉํ•œ ํ‘œํ˜„ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

์‹œ๊ฐ„ ๋ณต์žก๋„

์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•œ ๊ตฌํ˜„

class Graph {
  constructor() {
    this.adjacencyList = {};
  }

  addVertex(vertex) {
    if (!this.adjacencyList[vertex]) this.adjacencyList[vertex] = [];
  }

  addEdge(vertex1, vertex2) {
    if (!this.adjacencyList[vertex1]) this.addVertex(vertex1);
    if (!this.adjacencyList[vertex2]) this.addVertex(vertex2);

    this.adjacencyList[vertex1].push(vertex2);
    this.adjacencyList[vertex2].push(vertex1);
  }

  removeEdge(vertex1, vertex2) {
    this.adjacencyList[vertex1] = this.adjacencyList[vertex1].filter(
      (v) => v !== vertex2
    );
    this.adjacencyList[vertex2] = this.adjacencyList[vertex2].filter(
      (v) => v !== vertex1
    );
  }

  removeVertex(vertex) {
    for (let key in this.adjacencyList) {
      if (this.adjacencyList[key].includes(vertex)) {
        this.adjacencyList[key] = this.adjacencyList[key].filter(
          (v) => v !== vertex
        );
      }
    }

    delete this.adjacencyList[vertex];

    console.log('after this.adjacencyList[key]:', this.adjacencyList);
  }
}

let basicGraph = new Graph();

basicGraph.addVertex('A');
basicGraph.addVertex('B');

basicGraph.addEdge('A', 'B');
basicGraph.addEdge('A', 'C');
basicGraph.addEdge('A', 'D');
basicGraph.addEdge('B', 'C');

basicGraph.removeVertex('A');

console.log(basicGraph);

๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜

  1. ๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰(BFS, Breadth-First Search): ์‹œ์ž‘ ์ •์ ์—์„œ ๊ฐ€๊นŒ์šด ์ •์ ๋ถ€ํ„ฐ ํƒ์ƒ‰ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ํ(Queue)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  2. ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰(DFS, Depth-First Search): ์‹œ์ž‘ ์ •์ ์—์„œ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ๊นŠ์ด ํƒ์ƒ‰ํ•˜๋‹ค๊ฐ€ ๋” ์ด์ƒ ๊ฐˆ ์ˆ˜ ์—†์œผ๋ฉด ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ํƒ์ƒ‰ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ์Šคํƒ(Stack)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์žฌ๊ท€ ํ˜ธ์ถœ๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

๋„ˆ๋น„ ์šฐ์„  ํƒ์ƒ‰(BFS) ๊ตฌํ˜„

 bfs(vertex) {
    // This function should accept a starting vertex
    // Create a queue (you can use an array) and place the starting vertex in it
    // Create an array to store the node visited
    // Create an object to store nodes visited
    // Mark the starting vertex as visited
    // Loop as long as there is anything in the queue
    // Remove the first vertex from the queue and push it into the array stores nodes visited
    // Loop over each vertex in the adjacency list for the vertex you are visiting
    // If it is not inside the object that stores nodes visited, mark it as visited and enqueue that vertex

    let queue = [];
    let results = [];
    let visited = {};
    let targetVertex;

    queue.push(vertex);
    visited[vertex] = true;

    while (queue.length) {
      console.log('queue:', queue);
      targetVertex = queue.shift();
      results.push(targetVertex);

      this.adjacencyList[targetVertex].forEach((neighbor) => {
        if (!visited[neighbor]) {
          visited[neighbor] = true;
          queue.push(neighbor);
        }
      });
    }

    return results;
  }

๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰(DFS) ๊ตฌํ˜„ - ์žฌ๊ท€

  dfRecursive(startVertex) {
    // The function should accept a starting node
    // Create a 'results' variable to store the end result, to be returned at the very end
    // Create an object 'visitied' to store visited vertices
    // Create a helper function which accepts a vertex
    // The helper function should return early if the vertex is empty
    // The helper function should place the vertex it accepts into the visited object and push that vertex into the result array
    // Loop over all of the values in the adjacencyList for that vertex
    // If any of those values have not been visited, recursively invoke the helper function with that vertext
    let results = [];
    let visited = {};
    let adjacencyList = this.adjacencyList;
    /**
     * { A : true, B: true, ... }
     */

    function helper(vertex) {
      if (!vertex) return null;
      visited[vertex] = true;
      results.push(vertex);

      adjacencyList[vertex].forEach((neighbor) => {
        if (!visited[neighbor]) {
          return helper(neighbor);
        }
      });
    }

    helper(startVertex);

    return results;
  }

  /**
const list = {
  A: ['B', 'C'],
  B: ['A', 'D'],
  C: ['A', 'E'],
  D: ['B', 'E', 'F'],
  E: ['C', 'D', 'F'],
  F: ['D', 'E'],
};
 */

/**
 * basicGraph.dfRecursive('A')
 *
 * [ 'A', 'B', 'D', 'E', 'C', 'F' ]
 */

๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰(DFS) ๊ตฌํ˜„ - ์ˆœํ™˜

dfIterative(vertex) {
    // The function should accept a starting node
    // Create a stack to help use keep track of vertices (use a list/ array)
    // Create a list to store the end result, to be returned at the very end
    // Create an object to store visited vertices
    // Add the starting vertex to the stack, and mark it visited
    // While the stack has something in it:
    // Pop the next vertext from the stack
    // If that vertext hasn't been visited yet:
    // Mark it as visited
    // Add it to the result list
    // Push all of its neighbors into the stack

    let stack = [];
    let results = [];
    let visited = {};
    let targetVertex;

    stack.push(vertex);
    visited[vertex] = true;

    while (stack.length) {
      console.log('stack:', stack);
      targetVertex = stack.pop();
      results.push(targetVertex);

      this.adjacencyList[targetVertex].forEach((neighbor) => {
        if (!visited[neighbor]) {
          visited[neighbor] = true;
          stack.push(neighbor);
        }
      });
    }

    return results;
  }

  /**
const list = {
  A: ['B', 'C'],
  B: ['A', 'D'],
  C: ['A', 'E'],
  D: ['B', 'E', 'F'],
  E: ['C', 'D', 'F'],
  F: ['D', 'E'],
};
 */

/**
 *basicGraph.dfIterative('A')
 *
 *  stack: [ 'A' ]
 *  stack: [ 'B', 'C' ]
 *  stack: [ 'B', 'E' ]
 *  stack: [ 'B', 'D', 'F' ]
 *  stack: [ 'B', 'D' ]
 *  stack: [ 'B' ]
 *
 *  [ 'A', 'C', 'E', 'F', 'D', 'B' ]
 */

๊ทธ๋ž˜ํ”„์˜ ์‘์šฉ

  1. ๋„คํŠธ์›Œํฌ: ์ปดํ“จํ„ฐ ๋„คํŠธ์›Œํฌ, ์†Œ์…œ ๋„คํŠธ์›Œํฌ ๋“ฑ์—์„œ ๋…ธ๋“œ ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  2. ๊ฒฝ๋กœ ์ฐพ๊ธฐ: ์ง€๋„๋‚˜ ๊ธธ ์ฐพ๊ธฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  3. ์ผ์ • ๊ด€๋ฆฌ: ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ์—์„œ ์ž‘์—… ๊ฐ„์˜ ์˜์กด์„ฑ์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  4. ์ˆœ์œ„ ๊ณ„์‚ฐ: ํŽ˜์ด์ง€ ๋žญํฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๊ฐ™์€ ๊ฒ€์ƒ‰ ์—”์ง„์—์„œ ํŽ˜์ด์ง€์˜ ์ค‘์š”๋„๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜ํ”„๋Š” ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ์ž๋ฃŒ ๊ตฌ์กฐ๋กœ, ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

Dijkstra

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Dijkstra's Algorithm)์€ ๊ทธ๋ž˜ํ”„์—์„œ ํ•œ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ์œผ๋กœ์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐ€์ค‘์น˜๊ฐ€ ์Œ์ˆ˜๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ฐœ๋…

  1. ์‹œ์ž‘ ์ •์  ์„ ํƒ: ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์‹œ์ž‘ ์ •์ ์—์„œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ตœ๋‹จ ๊ฒฝ๋กœ ์ง‘ํ•ฉ: ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ํ™•์ •ํ•œ ์ •์ ๋“ค์˜ ์ง‘ํ•ฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฏธํ™•์ • ์ง‘ํ•ฉ: ์•„์ง ์ตœ๋‹จ ๊ฒฝ๋กœ๊ฐ€ ํ™•์ •๋˜์ง€ ์•Š์€ ์ •์ ๋“ค์˜ ์ง‘ํ•ฉ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ฑฐ๋ฆฌ ๋ฐฐ์—ด: ์‹œ์ž‘ ์ •์ ์—์„œ ๊ฐ ์ •์ ๊นŒ์ง€์˜ ํ˜„์žฌ๊นŒ์ง€ ๋ฐœ๊ฒฌ๋œ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ์—๋Š” ์‹œ์ž‘ ์ •์ ์˜ ๊ฑฐ๋ฆฌ๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ๋‚˜๋จธ์ง€ ์ •์ ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๋ฌดํ•œ๋Œ€๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  5. ์ด์›ƒ ์ •์  ์—…๋ฐ์ดํŠธ: ํ˜„์žฌ ์ •์ ์—์„œ ์ธ์ ‘ํ•œ ์ •์ ๋“ค๋กœ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ๋” ์งง์€ ๊ฒฝ๋กœ๋ฅผ ๋ฐœ๊ฒฌํ•˜๋ฉด ๊ฑฐ๋ฆฌ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  6. ๋ฐ˜๋ณต: ๋ชจ๋“  ์ •์ ์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ๊ฐ€ ํ™•์ •๋  ๋•Œ๊นŒ์ง€ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ณผ์ •

๋‹ค์ต์ŠคํŠธ๋ผ

  1. ์‹œ์ž‘ ์ •์ ์„ ์„ค์ •ํ•˜๊ณ , ์‹œ์ž‘ ์ •์ ์˜ ๊ฑฐ๋ฆฌ๋ฅผ 0์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ˜„์žฌ ์ •์ ์—์„œ ์ธ์ ‘ํ•œ ๋ชจ๋“  ์ •์ ์˜ ๊ฑฐ๋ฆฌ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
  3. ์•„์ง ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ •์  ์ค‘ ๊ฐ€์žฅ ๊ฑฐ๋ฆฌ๊ฐ€ ์งง์€ ์ •์ ์„ ์„ ํƒํ•˜์—ฌ, ๊ทธ ์ •์ ์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  4. ์ด ๊ณผ์ •์„ ๋ชจ๋“  ์ •์ ์ด ๋ฐฉ๋ฌธ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์ตํŠธ๋ผ ๋ฉ”์„œ๋“œ์˜ ์˜์‚ฌ์ฝ”๋“œ

  • ์ด ํ•จ์ˆ˜๋Š” ์‹œ์ž‘ ์ •์ ๊ณผ ๋ ์ •์ ์„ ๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด(์ด๋ฅผ distances๋ผ๊ณ  ๋ถ€๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค)๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ ํ‚ค๋ฅผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์ •์ ์œผ๋กœ ์„ค์ •ํ•˜๋˜, ์‹œ์ž‘ ์ •์ ์€ 0์˜ ๊ฐ’์„ ๊ฐ€์ง€๋„๋ก ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฌดํ•œ๋Œ€์˜ ๊ฐ’์„ ๊ฐ€์ง€๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • distances ๊ฐ์ฒด์— ๊ฐ’์„ ์„ค์ •ํ•œ ํ›„, ์‹œ์ž‘ ์ •์ ์„ ์ œ์™ธํ•œ ๊ฐ ์ •์ ์„ ์šฐ์„ ์ˆœ์œ„ ํ์— ๋ฌดํ•œ๋Œ€์˜ ์šฐ์„ ์ˆœ์œ„๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์ž‘ ์ •์ ์€ ์šฐ๋ฆฌ๊ฐ€ ์‹œ์ž‘ํ•˜๋Š” ๊ณณ์ด๋ฏ€๋กœ ์šฐ์„ ์ˆœ์œ„๊ฐ€ 0์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • previous๋ผ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ  ๊ฐ ํ‚ค๋ฅผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์˜ ๋ชจ๋“  ์ •์ ์œผ๋กœ ์„ค์ •ํ•˜๋˜, ๊ฐ’์€ null๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์šฐ์„ ์ˆœ์œ„ ํ์— ํ•ญ๋ชฉ์ด ์žˆ๋Š” ๋™์•ˆ ๋ฐ˜๋ณต์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
    • ์šฐ์„ ์ˆœ์œ„ ํ์—์„œ ์ •์ ์„ dequeueํ•ฉ๋‹ˆ๋‹ค.
    • ํ•ด๋‹น ์ •์ ์ด ๋ ์ •์ ๊ณผ ๊ฐ™์œผ๋ฉด - ์™„๋ฃŒ์ž…๋‹ˆ๋‹ค!
    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น ์ •์ ์˜ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ๊ฐ’์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.
      • ์‹œ์ž‘ ์ •์ ์—์„œ ํ•ด๋‹น ์ •์ ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.
      • ๊ทธ ๊ฑฐ๋ฆฌ๊ฐ€ ํ˜„์žฌ distances ๊ฐ์ฒด์— ์ €์žฅ๋œ ๊ฐ’๋ณด๋‹ค ์ž‘์œผ๋ฉด
        • distances ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ์šด ๋” ์งง์€ ๊ฑฐ๋ฆฌ๋กœ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
        • previous ๊ฐ์ฒด์— ํ•ด๋‹น ์ •์ ์„ ํฌํ•จํ•˜๋„๋ก ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
        • ์‹œ์ž‘ ๋…ธ๋“œ๋กœ๋ถ€ํ„ฐ์˜ ์ด ๊ฑฐ๋ฆฌ๋กœ ์ •์ ์„ ํ์— enqueueํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„

class PriorityQueue {
  constructor() {
    this.values = [];
  }
  enqueue(val, priority) {
    this.values.push({ val, priority });
    this.sort();
  }
  dequeue() {
    return this.values.shift();
  }
  sort() {
    this.values.sort((a, b) => a.priority - b.priority);
  }
}

class WeightedGraph {
  constructor() {
    this.adjacencyList = {};
  }
  addVertex(vertex) {
    if (!this.adjacencyList[vertex]) this.adjacencyList[vertex] = [];
  }
  addEdge(vertex1, vertex2, weight) {
    this.adjacencyList[vertex1].push({ node: vertex2, weight });
    this.adjacencyList[vertex2].push({ node: vertex1, weight });
  }
  Dijkstra(start, finish) {
    // nodes dequeue ํ•  ๋•Œ, ๊ฐ€์ค‘์น˜๊ฐ€ ๋‚ฎ์€ ๊ฒƒ์„ ๋จผ์ € ๋ฝ‘์•„ ์ˆœํšŒํ•˜๊ธฐ ์œ„ํ•œ ์šฐ์„ ์ˆœ์œ„ ํ ํด๋ž˜์Šค
    const nodes = new PriorityQueue();
    // distances - ์‹œ์ž‘ ์ •์ ์„ ๊ธฐ์ค€์œผ๋กœ ๊ฐ€์žฅ ์งง์€ ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•ด๋‘๋Š” ๊ฐ์ฒด
    const distances = {};
    // previous - ์ตœ์ข…์ ์œผ๋กœ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ธฐ์–ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด
    const previous = {};
    // target - ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ๋ฐฉ๋ฌธํ•˜๋Š” ๋…ธ๋“œ
    let target;
    // path - ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•ด์„œ ๋ฐ˜ํ™˜ํ•  ๋ฐฐ์—ด
    let path = [];

    //build up initial state
    for (let vertex in this.adjacencyList) {
      if (vertex === start) {
        distances[vertex] = 0;
        nodes.enqueue(vertex, 0);
      } else {
        distances[vertex] = Infinity;
        nodes.enqueue(vertex, Infinity);
      }
      previous[vertex] = null;
    }

    console.log('nodes.values:', nodes.values);
    console.log('distances:', distances);
    console.log('previous:', previous);
    console.log('adjacencyList:', this.adjacencyList);
    // as long as there is something to visit
    while (nodes.values.length) {
      target = nodes.dequeue().val;
      if (target === finish) {
        //WE ARE DONE
        //BUILD UP PATH TO RETURN AT END
        while (previous[target]) {
          path.push(target);
          target = previous[target];
        }
        break;
      }
      if (target || distances[target] !== Infinity) {
        for (let neighbor in this.adjacencyList[target]) {
          //find neighboring node
          let nextNode = this.adjacencyList[target][neighbor];
          //calculate new distance to neighboring node
          let newDistance = distances[target] + nextNode.weight;

          console.log('nextNode:', nextNode);
          console.log('newDistance:', newDistance);

          if (newDistance < distances[nextNode.node]) {
            //updating new target distance to neighbor
            distances[nextNode.node] = newDistance;
            //updating previous - How we got to neighbor
            previous[nextNode.node] = target;
            //enqueue in priority queue with new priority
            nodes.enqueue(nextNode.node, newDistance);
          }
        }
      }
    }
    return path.concat(target).reverse();
  }
}

var graph = new WeightedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');

graph.addEdge('A', 'B', 4);
graph.addEdge('A', 'C', 2);
graph.addEdge('B', 'E', 3);
graph.addEdge('C', 'D', 2);
graph.addEdge('C', 'F', 4);
graph.addEdge('D', 'E', 3);
graph.addEdge('D', 'F', 1);
graph.addEdge('E', 'F', 1);

console.log(graph.Dijkstra('A', 'E'));

// ["A", "C", "D", "F", "E"]

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

  • ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ: (O(V^2))
  • ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ (์˜ˆ: ํž™ ์‚ฌ์šฉ):
    • ์‚ฝ์ž…/์‚ญ์ œ: (O(log V))
    • ์ด ์‹œ๊ฐ„ ๋ณต์žก๋„: (O((V + E) log V))

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํŠน์ง•

  1. ๋‹จ์ผ ์‹œ์ž‘์ : ์‹œ์ž‘ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ์œผ๋กœ์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.
  2. ๋น„์Œ์ˆ˜ ๊ฐ€์ค‘์น˜: ๊ฐ„์„ ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์Œ์ˆ˜์ธ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  3. ํšจ์œจ์„ฑ: ์šฐ์„ ์ˆœ์œ„ ํ(ํž™)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํฐ ๊ทธ๋ž˜ํ”„์—์„œ๋„ ๋น„๊ต์  ํšจ์œจ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋„คํŠธ์›Œํฌ ๋ผ์šฐํŒ…, ์ง€๋„ ์„œ๋น„์Šค, ๊ตํ†ต ์‹œ์Šคํ…œ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Dynamic Programming

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Dynamic Programming, DP)์€ ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ๋” ์ž‘์€ ํ•˜์œ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด ํ•ด๊ฒฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ค๊ณ„ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ ํ•˜์œ„ ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ฃผ๋กœ ์ตœ์ ํ™” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์†์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค: **์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ(Optimal Substructure)**์™€ ์ค‘๋ณต ๋ถ€๋ถ„ ๋ฌธ์ œ(Overlapping Subproblems).

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๊ฐœ๋…

  1. ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ(Optimal Substructure):
    • ํฐ ๋ฌธ์ œ์˜ ์ตœ์  ํ•ด๊ฐ€ ๊ทธ ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ์ตœ์  ํ•ด๋กœ๋ถ€ํ„ฐ ์œ ๋„๋  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์ตœ๋‹จ ๊ฒฝ๋กœ ๋ฌธ์ œ์—์„œ ์ „์ฒด ๊ฒฝ๋กœ์˜ ์ตœ์  ํ•ด๋Š” ๊ทธ ๊ฒฝ๋กœ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ถ€๋ถ„ ๊ฒฝ๋กœ๋“ค์˜ ์ตœ์  ํ•ด๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ค‘๋ณต ๋ถ€๋ถ„ ๋ฌธ์ œ(Overlapping Subproblems):
    • ๋™์ผํ•œ ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณตํ•˜์—ฌ ๊ณ„์‚ฐ๋˜๋Š” ์†์„ฑ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
    • ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์ด๋Ÿฌํ•œ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ด๋ฏธ ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ ‘๊ทผ ๋ฐฉ์‹

  1. ํƒ‘๋‹ค์šด(๋ฉ”๋ชจ์ด์ œ์ด์…˜, Memoization):
    • ์žฌ๊ท€์  ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ, ๋ฌธ์ œ๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ๋‚˜๋ˆ„๊ณ , ๊ฐ ํ•˜์œ„ ๋ฌธ์ œ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜์—ฌ ํ•„์š”ํ•  ๋•Œ ๋‹ค์‹œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ํ•„์š”ํ•  ๋•Œ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ, ์ฒ˜์Œ์—๋Š” ๊ณ„์‚ฐํ•˜์ง€ ์•Š๊ณ  ์š”์ฒญ ์‹œ ๊ณ„์‚ฐํ•˜์—ฌ ์บ์‹œ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ฐ”ํ…€์—…(ํ…Œ์ด๋ธ”๋ง, Tabulation):
    • ๋ฐ˜๋ณต์  ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ, ์ž‘์€ ํ•˜์œ„ ๋ฌธ์ œ๋ถ€ํ„ฐ ์ฐจ๋ก€๋กœ ํ•ด๊ฒฐํ•˜๋ฉด์„œ ์ƒ์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
    • ๋ชจ๋“  ํ•˜์œ„ ๋ฌธ์ œ๋ฅผ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•˜์—ฌ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜๊ณ , ์ด๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์˜ˆ์ œ

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์€ ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์ž…๋‹ˆ๋‹ค. ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜ \(F(n)\)์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋ฉ๋‹ˆ๋‹ค:

ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์„ ์ตœ์ ํ™” ์—†์ด ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” O(2^n) ์ž…๋‹ˆ๋‹ค.

์‹œ๊ฐ„ ๋ณต์žก๋„

function fib(n) {
  if (n <= 2) return 1;

  return fib(n - 1) + fib(n - 2);
}

console.log(fib(2)); // 13

๋ฉ”๋ชจ์ด์ œ์ด์…˜์„ ์‚ฌ์šฉํ•œ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด (ํƒ‘๋‹ค์šด ๋ฐฉ์‹)

function fib_memo(n, memo = []) {
  if (memo[n] !== undefined) return memo[n];
  if (n <= 2) return 1;

  const res = fib(n - 1, memo) + fib(n - 2, memo);
  memo[n] = res;

  console.log('memo:', memo);

  return res;
}

console.log(fib_memo(10));

/**
 * memo: [ <3 empty items>, 2 ]
 * memo: [ <3 empty items>, 2, 3 ]
 * memo: [ <3 empty items>, 2, 3, 5 ]
 * memo: [ <3 empty items>, 2, 3, 5, 8 ]
 * memo: [ <3 empty items>, 2, 3, 5, 8, 13 ]
 * memo: [ <3 empty items>, 2, 3, 5, 8, 13, 21 ]
 * memo: [ <3 empty items>, 2, 3, 5, 8, 13, 21, 34 ]
 * memo: [ <3 empty items>, 2, 3, 5, 8, 13, 21, 34, 55 ]
55
 */

ํ…Œ์ด๋ธ”๋ง์„ ์‚ฌ์šฉํ•œ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด (๋ฐ”ํ…€์—… ๋ฐฉ์‹)

function fib_tabulation(n) {
  if (n <= 2) return 1;
  let fibNums = [0, 1, 1];
  for (let i = 3; i <= n; i++) {
    fibNums[i] = fibNums[i - 1] + fibNums[i - 2];
  }

  console.log('fibNums:', fibNums);

  return fibNums[n];
}

console.log(fib_tabulation(10));

/**
 * fibNums: [
   0, 1,  1,  2,  3,
   5, 8, 13, 21, 34,
  55
]
 */

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์ง•

  1. ์‹œ๊ฐ„ ๋ณต์žก๋„ ๊ฐœ์„ : ์ค‘๋ณต ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ณ , ๊ฐ ํ•˜์œ„ ๋ฌธ์ œ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ํฌ๊ฒŒ ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.
  2. ๊ณต๊ฐ„ ๋ณต์žก๋„: ๋ฉ”๋ชจ์ด์ œ์ด์…˜์ด๋‚˜ ํ…Œ์ด๋ธ”์„ ์ €์žฅํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ถ”๊ฐ€ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜์ง€๋งŒ, ์‹œ๊ฐ„ ๋ณต์žก๋„ ๊ฐœ์„ ์— ๋น„ํ•ด ํฐ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์ ์šฉ ๋ฒ”์œ„: ์ตœ์ ํ™” ๋ฌธ์ œ, ๊ฒฝ๋กœ ์ฐพ๊ธฐ ๋ฌธ์ œ, ๋ถ€๋ถ„ ์ง‘ํ•ฉ ๋ฌธ์ œ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฌธ์ œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.