- Frequency Counters
- Multipleย Pointers
- Sliding Window
- Divide and conquer
- Recursion
- Linear Search
- Naive String Search
- Binary Search
- Bubble Sort
- Selection Sort
- Insertion Sort
- Merge Sort
- Quick Sort
- Single Linked List
- Dobule Linked List
- Stack
- Queue
- Binary Search Tree
- Breadth First Search
- Depth First Search
- Binary Heap
- Priority Queue
- Hash Table
- graph
- Dijkstra
- Dynamic Programming
Frequency Counters๋ ํ๋ก๊ทธ๋๋ฐ์์ ํน์ ์์์ ๋ฐ์ ๋น๋๋ฅผ ํจ์จ์ ์ผ๋ก ๊ณ์ฐํ๋ ์๊ณ ๋ฆฌ์ฆ ๊ธฐ๋ฒ์ ๋๋ค. ์ฃผ๋ก ๋ฐฐ์ด, ๋ฌธ์์ด ๋๋ ๋ค๋ฅธ ์๋ฃ ๊ตฌ์กฐ ๋ด์์ ์์์ ๋น๋๋ฅผ ์ธ์ด์ผ ํ ๋ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์ผ๋ฐ์ ์ผ๋ก ์๊ฐ ๋ณต์ก๋๋ฅผ ์ค์ด๊ณ ์ฝ๋๋ฅผ ๋ณด๋ค ํจ์จ์ ์ผ๋ก ๋ง๋ค๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
Frequency Counter์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์๋ฃ ๊ตฌ์กฐ ์ ํ: ์ฃผ๋ก ํด์๋งต(๋๋ ๊ฐ์ฒด)์ ์ฌ์ฉํ์ฌ ๊ฐ ์์์ ๋ฐ์ ๋น๋๋ฅผ ์ ์ฅํฉ๋๋ค.
- ๋ฐ๋ณต๋ฌธ ์ฌ์ฉ: ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ ์ํํ๋ฉด์ ๊ฐ ์์์ ๋น๋๋ฅผ ํด์๋งต์ ๊ธฐ๋กํฉ๋๋ค.
- ๊ฒฐ๊ณผ ๋ถ์: ํ์์ ๋ฐ๋ผ ๋น๋ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
์ด ์๋ฐ์คํฌ๋ฆฝํธ ๊ตฌํ์ ๊ฐ ๋ฐฐ์ด ๋๋ ๋ฌธ์์ด์ ํ ๋ฒ๋ง ์ํํ๊ธฐ ๋๋ฌธ์ ์๊ฐ ๋ณต์ก๋๋ 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 ๋ฌธ: ๊ฐ์ฒด์ ํค๋ฅผ ์ํํ๋ค.
*/
// 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๋ฅผ ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๋ ์ผ๋ฐ์ ์ผ๋ก O(n)์ ๋๋ค. ์ด๋ ๋ฐฐ์ด์ด๋ ๋ฌธ์์ด์ ํ ๋ฒ๋ง ์ํํ๋ฉด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
Multiple Pointers ๊ธฐ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ๋ฌธ์ ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค:
- ๋ ๊ฐ์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ์ด ๋ด ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์์ ์ฐพ๊ธฐ
- ์ค๋ณต ์์ ์ ๊ฑฐ
- ๋ฌธ์์ด ๋ด ํน์ ํจํด ์ฐพ๊ธฐ
- ์ ๋ ฌ๋ ๋ฐฐ์ด์์ ํน์ ํฉ์ ๊ฐ์ง๋ ์ ์ฐพ๊ธฐ
// 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
// 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์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์๋์ฐ ์ค์ : ์ด๊ธฐ ์๋์ฐ ํฌ๊ธฐ๋ ์์์ ์ ์ค์ ํฉ๋๋ค.
- ์๋์ฐ ์ด๋: ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ํ๋์ฉ ์ด๋ํ๋ฉด์ ์๋์ฐ ๋ด ๊ฐ์ ๊ฐฑ์ ํฉ๋๋ค.
- ๊ฒฐ๊ณผ ๊ฐฑ์ : ์๋์ฐ ๋ด ๊ฐ์ ๊ธฐ์ค์ผ๋ก ํ์ํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐฑ์ ํฉ๋๋ค.
๋ค์์ ๊ณ ์ ๋ ํฌ๊ธฐ์ ์๋์ฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ์ด ๋ด ์ฐ์๋ ์์๋ค์ ์ต๋ ํฉ์ ์ฐพ๋ ์์ ์ ๋๋ค.
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): ํด๊ฒฐํด์ผ ํ ๋ฌธ์ ๋ฅผ ๋์ผํ ์ ํ์ ๋ ์์ ๋ถ๋ถ ๋ฌธ์ ๋ก ๋๋๋๋ค.
- ์ ๋ณต(Conquer): ๊ฐ ๋ถ๋ถ ๋ฌธ์ ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํด๊ฒฐํฉ๋๋ค. ๋ถ๋ถ ๋ฌธ์ ๊ฐ ์ถฉ๋ถํ ์์ผ๋ฉด ์ง์ ํด๊ฒฐํฉ๋๋ค.
- ๊ฒฐํฉ(Combine): ๋ถ๋ถ ๋ฌธ์ ์ ํด๋ฅผ ํฉ์ณ์ ์๋ ๋ฌธ์ ์ ํด๋ฅผ ์ป์ต๋๋ค.
๋ณํฉ ์ ๋ ฌ์ 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]));
์ด์ง ํ์์ ์ ๋ ฌ๋ ๋ฐฐ์ด์์ ํน์ ๊ฐ์ ์ฐพ๋ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๋ฐฐ์ด์ ๋ฐ์ผ๋ก ๋๋์ด ์ฐพ๊ณ ์ ํ๋ ๊ฐ์ด ์ด๋ ์ชฝ์ ์๋์ง ํ์ธํ ํ, ํด๋น ์ ๋ฐ์์ ๋ค์ ํ์์ ๋ฐ๋ณตํฉ๋๋ค.
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)๋ ํจ์๊ฐ ์๊ธฐ ์์ ์ ํธ์ถํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ธฐ๋ฒ์ ๋๋ค. ์ฌ๊ท๋ ๋ฌธ์ ๋ฅผ ์์ ๋ถ๋ถ ๋ฌธ์ ๋ก ๋๋์ด ํด๊ฒฐํ ๋ ํนํ ์ ์ฉํ๋ฉฐ, Divide and Conquer์ ๊ฐ์ ์๊ณ ๋ฆฌ์ฆ ๊ธฐ๋ฒ๊ณผ ์์ฃผ ๊ฒฐํฉ๋ฉ๋๋ค. ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๊ธฐ๋ณธ ์กฐ๊ฑด(base case)๊ณผ ์ฌ๊ท ์กฐ๊ฑด(recursive case)์ ์ ์ํด์ผ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ์กฐ๊ฑด (Base Case): ์ฌ๊ท ํธ์ถ์ ๋ฉ์ถ๋ ์กฐ๊ฑด์ ๋๋ค. ๋ ์ด์ ๋ฌธ์ ๋ฅผ ์ชผ๊ฐค ์ ์์ ๋ ๊ธฐ๋ณธ ์กฐ๊ฑด์ ์ฌ์ฉํ์ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ฌ๊ท ์กฐ๊ฑด (Recursive Case): ํจ์๊ฐ ์๊ธฐ ์์ ์ ํธ์ถํ๋ ๋ถ๋ถ์ ๋๋ค. ๋ฌธ์ ๋ฅผ ๋ ์์ ๋ถ๋ถ์ผ๋ก ์ชผ๊ฐ๊ณ , ๊ทธ ๋ถ๋ถ์ ํด๊ฒฐํ๊ธฐ ์ํด ๋ค์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
ํฉํ ๋ฆฌ์ผ์ 1๋ถํฐ n๊น์ง์ ์ ์๋ฅผ ๋ชจ๋ ๊ณฑํ ๊ฐ์ ๋๋ค. ์ฌ๊ท๋ฅผ ์ฌ์ฉํ์ฌ ํฉํ ๋ฆฌ์ผ์ ๊ณ์ฐํ ์ ์์ต๋๋ค.
function factorial(n) {
if (n === 0) return 1; // ๊ธฐ๋ณธ ์กฐ๊ฑด
return n * factorial(n - 1); // ์ฌ๊ท ์กฐ๊ฑด
}
console.log(factorial(5)); // 120
ํผ๋ณด๋์น ์์ด์ ๊ฐ ํญ์ ์์ ๋ ํญ์ ํฉ์ ๋๋ค. ์ฌ๊ท๋ฅผ ์ฌ์ฉํ์ฌ ํผ๋ณด๋์น ์๋ฅผ ๊ณ์ฐํ ์ ์์ต๋๋ค.
function fibonacci(n) {
if (n <= 1) return n; // ๊ธฐ๋ณธ ์กฐ๊ฑด
return fibonacci(n - 1) + fibonacci(n - 2); // ์ฌ๊ท ์กฐ๊ฑด
}
console.log(fibonacci(7)); // 13
์ฌ๊ท๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐฐ์ด์ ํฉ์ ๊ณ์ฐํ๋ ์์ ์ ๋๋ค.
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
- ์๋ฐ์คํฌ๋ฆฝํธ์ 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)์ ์ฌ์ฉํ๋ฉด ํจ์จ์ ์ผ๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค.
- ๊ธฐ๋ณธ ์กฐ๊ฑด์ ์ค์์ฑ: ๊ธฐ๋ณธ ์กฐ๊ฑด์ด ์์ผ๋ฉด ํจ์๊ฐ ๋ฌดํํ ํธ์ถ๋์ด ์คํ ์ค๋ฒํ๋ก(stack overflow)๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์ฌ๊ท ๊น์ด ์ ํ: ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ ์ฌ๊ท ํธ์ถ์ ์ต๋ ๊น์ด๋ฅผ ์ ํํฉ๋๋ค. ๊น์ด๊ฐ ๋๋ฌด ๊น์ผ๋ฉด ์คํ ์ค๋ฒํ๋ก๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๋ฉ๋ชจ์ด์ ์ด์ : ์ค๋ณต ๊ณ์ฐ์ ํผํ๊ธฐ ์ํด ๋ฉ๋ชจ์ด์ ์ด์ ์ ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ฌ๊ท๋ ๋ค์๊ณผ ๊ฐ์ ๋ค์ํ ๋ฌธ์ ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค:
- ํธ๋ฆฌ ๋ฐ ๊ทธ๋ํ ํ์ (์: DFS)
- ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ (์: ํต ์ ๋ ฌ, ๋ณํฉ ์ ๋ ฌ)
- ์กฐํฉ๋ก ๋ฌธ์ (์: ์์ด, ์กฐํฉ)
- ๋์ ๊ณํ๋ฒ ๋ฌธ์ ์์ ๋ถ๋ถ ๋ฌธ์ ํด๊ฒฐ
์ฌ๊ท๋ ๋ณต์กํ ๋ฌธ์ ๋ฅผ ๋จ์ํํ๊ณ , ์ฝ๋๋ฅผ ๋ณด๋ค ์ง๊ด์ ์ผ๋ก ์์ฑํ๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ ๋๊ตฌ์ ๋๋ค.
์ ํ ๊ฒ์(Linear Search)์ ๊ฐ์ฅ ๊ฐ๋จํ ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๋ก, ๋ฐฐ์ด์ด๋ ๋ฆฌ์คํธ์ ๊ฐ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ์์ ํน์ ์์๋ฅผ ์ฐพ๊ธฐ ์ํด ์ฒ์๋ถํฐ ๋๊น์ง ์์ฐจ์ ์ผ๋ก ์์๋ฅผ ํ๋์ฉ ๋น๊ตํ๋ ๋ฐฉ์์ ๋๋ค. ์ ํ ๊ฒ์์ ๊ตฌํ์ด ๋งค์ฐ ๊ฐ๋จํ์ง๋ง, ํจ์จ์ฑ์ด ๋จ์ด์ง๊ธฐ ๋๋ฌธ์ ์์ ๋ฐ์ดํฐ์ ์์ ์ฃผ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
์ ํ ๊ฒ์์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์์ฐจ์ ์ผ๋ก ๋น๊ต: ๋ฆฌ์คํธ์ ์ฒซ ๋ฒ์งธ ์์๋ถํฐ ๋ง์ง๋ง ์์๊น์ง ์์ฐจ์ ์ผ๋ก ๋น๊ตํฉ๋๋ค.
- ์ผ์นํ๋ ์์ ์ฐพ๊ธฐ: ๊ฒ์ํ๋ ค๋ ์์์ ์ผ์นํ๋ ์์๋ฅผ ์ฐพ์ผ๋ฉด ํด๋น ์์์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ผ์นํ๋ ์์๊ฐ ์๋ ๊ฒฝ์ฐ: ๋ฆฌ์คํธ์ ๋ชจ๋ ์์๋ฅผ ๋น๊ตํ ํ์๋ ๊ฒ์ํ๋ ค๋ ์์๋ฅผ ์ฐพ์ง ๋ชปํ๋ฉด -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)
- ๊ฒ์ํ๋ ค๋ ์์๊ฐ ๋ฆฌ์คํธ์ ์ฒซ ๋ฒ์งธ ์์์ธ ๊ฒฝ์ฐ์ ๋๋ค.
- ๋จ์ํจ: ์ ํ ๊ฒ์์ ๊ตฌํ์ด ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ๊ฒ์(Comparison Search): ์์๋ค์ ํ๋์ฉ ๋น๊ตํ์ฌ ๊ฒ์ํฉ๋๋ค.
- ์ ๋ ฌ ์ฌ๋ถ์ ๋ฌด๊ด: ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ง ์์๋ ๊ฒ์์ด ๊ฐ๋ฅํฉ๋๋ค.
- ์ ์๋ฆฌ ๊ฒ์(In-place Search): ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ๊ฐ๋จํ๊ณ ์ง๊ด์ : ๊ตฌํ์ด ์ฝ๊ณ ์ง๊ด์ ์ ๋๋ค.
- ์ ๋ ฌ ํ์ ์์: ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ง ์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์์ ๋ฐ์ดํฐ์ ์ ์ ์ฉ: ์์ ๋ฐ์ดํฐ์ ์ ๋ํด์๋ ํจ์จ์ ์ ๋๋ค.
- ๋นํจ์จ์ฑ: ํฐ ๋ฐ์ดํฐ์ ์ ๋ํด์๋ ๋นํจ์จ์ ์ด๋ฉฐ, ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
- ์๊ฐ ๋ณต์ก๋: ์๊ฐ ๋ณต์ก๋๊ฐ O(n)์ผ๋ก, ์์์ ์๊ฐ ๋ง์์ง์๋ก ๊ฒ์ ์๊ฐ์ด ์ ํ์ ์ผ๋ก ์ฆ๊ฐํฉ๋๋ค.
์ ํ ๊ฒ์์ ๊ฐ๋จํ๊ณ ๊ตฌํ์ด ์ฌ์ด ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ์์ ๋ฐ์ดํฐ์ ์ด๋ ์ ๋ ฌ๋์ง ์์ ๋ฆฌ์คํธ์ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋, ํฐ ๋ฐ์ดํฐ์ ์ ๋ํด์๋ ํจ์จ์ฑ์ด ๋จ์ด์ง๋ฏ๋ก, ์ด์ง ๊ฒ์(Binary Search)๊ณผ ๊ฐ์ ๋ ํจ์จ์ ์ธ ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด์ง ๊ฒ์์ ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์๊ฐ ๋ณต์ก๋๊ฐ O(log n)์ผ๋ก ํจ์ฌ ํจ์จ์ ์ ๋๋ค.
Naive String Search๋ ๋ฌธ์์ด ๋ด์์ ํน์ ํจํด์ ์ฐพ๊ธฐ ์ํ ๋จ์ํ๊ณ ์ง๊ด์ ์ธ ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ํ ์คํธ์ ๊ฐ ์์น์์ ํจํด์ด ์ผ์นํ๋์ง ํ์ธํ๋ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค. ์ด ๊ณผ์ ์ ๋งค์ฐ ์ง๊ด์ ์ด์ง๋ง, ๋นํจ์จ์ ์ผ ์ ์์ต๋๋ค. ํนํ ๊ธด ํ ์คํธ์ ํจํด์ ๊ฒฝ์ฐ ๋ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
Naive String Search์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํ ์คํธ์ ๊ฐ ์์น์์ ํจํด ํ์ธ: ํ ์คํธ์ ์ฒซ ๋ฒ์งธ ๋ฌธ์๋ถํฐ ์์ํ์ฌ, ํจํด์ ๊ธธ์ด๋งํผ์ ๋ฌธ์๊ฐ ํจํด๊ณผ ์ผ์นํ๋์ง ํ์ธํฉ๋๋ค.
- ์ผ์น ์ฌ๋ถ ํ๋จ: ์ผ์นํ๋ ๊ฒฝ์ฐ ํด๋น ์์น๋ฅผ ๊ธฐ๋กํ๊ณ , ์ผ์นํ์ง ์๋ ๊ฒฝ์ฐ ๋ค์ ์์น๋ก ์ด๋ํ์ฌ ๋ค์ ํ์ธํฉ๋๋ค.
- ๋ฐ๋ณต: ํ ์คํธ์ ๋๊น์ง ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ 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์ ํจํด์ ๊ธธ์ด์ ๋๋ค.
- ๋จ์ํจ: ๊ตฌํ์ด ๋งค์ฐ ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ ๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ๊ฒ์: ํจํด์ ๊ฐ ๋ฌธ์์ ํ ์คํธ์ ๊ฐ ์์น๋ฅผ ๋น๊ตํฉ๋๋ค.
- ์ ๋ ฌ ํ์ ์์: ํ ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ ํ์๊ฐ ์์ต๋๋ค.
- ์ ์๋ฆฌ ๊ฒ์: ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฑฐ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ๊ฐ๋จํ ๊ตฌํ: ์๊ณ ๋ฆฌ์ฆ์ด ๋งค์ฐ ์ง๊ด์ ์ด๊ณ ์ดํดํ๊ธฐ ์ฝ์ต๋๋ค.
- ๋ณดํธ์ ์ฌ์ฉ: ํ ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ ํ์๊ฐ ์์ด ๋ค์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋นํจ์จ์ฑ: ๊ธด ํ ์คํธ์ ํจํด์ ๋ํด์๋ ๋งค์ฐ ๋นํจ์จ์ ์ ๋๋ค.
- ์๊ฐ ๋ณต์ก๋: ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋๊ฐ O(n * m)์ผ๋ก, ๋ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ๋นํด ๋๋ฆด ์ ์์ต๋๋ค.
๊ธด ํ ์คํธ๋ ํจํด์ ๋ค๋ฃฐ ๋ ๋ ํจ์จ์ ์ธ ๋ฌธ์์ด ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ด ํ์ํ ์ ์์ต๋๋ค. ๋ค์๊ณผ ๊ฐ์ ์๊ณ ๋ฆฌ์ฆ๋ค์ด ์์ต๋๋ค:
- Knuth-Morris-Pratt (KMP) ์๊ณ ๋ฆฌ์ฆ: ํจํด ๋ด์์์ ๋ถ๋ถ ์ผ์น๋ฅผ ์ด์ฉํ์ฌ ๊ฒ์ ์๋๋ฅผ ํฅ์์ํต๋๋ค.
- Boyer-Moore ์๊ณ ๋ฆฌ์ฆ: ํจํด์ ๋ค์์ ์์ผ๋ก ๊ฒ์ํ์ฌ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ์ ๋ ๋ ํฐ ํญ์ผ๋ก ๊ฒ์ ๋ฒ์๋ฅผ ์ด๋ํฉ๋๋ค.
- Rabin-Karp ์๊ณ ๋ฆฌ์ฆ: ํด์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํจํด๊ณผ ํ ์คํธ์ ์๋ธ์คํธ๋ง์ ๋น๊ตํฉ๋๋ค.
Naive String Search๋ ๋จ์ํ๊ณ ๊ตฌํ์ด ์ฌ์ด ๋ฌธ์์ด ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์งง์ ํ ์คํธ์ ํจํด์ ๊ฒฝ์ฐ ์ฌ์ฉํ๊ธฐ์ ์ ํฉํ์ง๋ง, ๊ธด ํ ์คํธ์ ํจํด์ ๋ค๋ฃฐ ๋๋ ๋ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํจ์จ์ ์ธ ๋ฌธ์์ด ๊ฒ์์ ์ํด KMP, Boyer-Moore, Rabin-Karp์ ๊ฐ์ ์๊ณ ๋ฆฌ์ฆ์ ๊ณต๋ถํ๊ณ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
์ด์ง ํ์(Binary Search)์ ํจ์จ์ ์ธ ๊ฒ์ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ์ ๋ ฌ๋ ๋ฐฐ์ด์ด๋ ๋ฆฌ์คํธ์์ ํน์ ์์๋ฅผ ์ฐพ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค. ์ด์ง ํ์์ ๋งค๋ฒ ๊ฒ์ ๋ฒ์๋ฅผ ๋ฐ์ผ๋ก ์ค์ด๊ธฐ ๋๋ฌธ์ ์๊ฐ ๋ณต์ก๋๊ฐ O(log n)์ผ๋ก ๋งค์ฐ ํจ์จ์ ์ ๋๋ค.
์ด์ง ํ์์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ค๊ฐ ์์ ์ ํ: ๊ฒ์ ๋ฒ์์ ์ค๊ฐ ์์๋ฅผ ์ ํํฉ๋๋ค.
- ๋น๊ต: ์ค๊ฐ ์์์ ๊ฒ์ํ๋ ค๋ ์์๋ฅผ ๋น๊ตํฉ๋๋ค.
- ์ผ์นํ๋ ๊ฒฝ์ฐ: ์์๋ฅผ ์ฐพ์ผ๋ฉด ํด๋น ์์์ ์ธ๋ฑ์ค๋ฅผ ๋ฐํํฉ๋๋ค.
- ์์ ๊ฒฝ์ฐ: ๊ฒ์ํ๋ ค๋ ์์๊ฐ ์ค๊ฐ ์์๋ณด๋ค ์์ผ๋ฉด, ๊ฒ์ ๋ฒ์๋ฅผ ์ค๊ฐ ์์์ ์ผ์ชฝ ๋ถ๋ถ์ผ๋ก ์ค์ ๋๋ค.
- ํฐ ๊ฒฝ์ฐ: ๊ฒ์ํ๋ ค๋ ์์๊ฐ ์ค๊ฐ ์์๋ณด๋ค ํฌ๋ฉด, ๊ฒ์ ๋ฒ์๋ฅผ ์ค๊ฐ ์์์ ์ค๋ฅธ์ชฝ ๋ถ๋ถ์ผ๋ก ์ค์ ๋๋ค.
- ๋ฐ๋ณต: ๊ฒ์ ๋ฒ์๊ฐ ์์ ๋๊น์ง 1~2๋ฒ ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
- ์ฐพ์ง ๋ชปํ ๊ฒฝ์ฐ: ๊ฒ์ ๋ฒ์๊ฐ ์์ด์ง๋ฉด, ์์๊ฐ ๋ฆฌ์คํธ์ ์๋ค๋ ๋ป์ด๋ฏ๋ก -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)
- ๊ฒ์ํ๋ ค๋ ์์๊ฐ ์ค๊ฐ ์์์ธ ๊ฒฝ์ฐ์ ๋๋ค.
- ํจ์จ์ฑ: ์๊ฐ ๋ณต์ก๋๊ฐ O(log n)์ผ๋ก ๋งค์ฐ ํจ์จ์ ์ ๋๋ค.
- ์ ๋ ฌ๋ ๋ฆฌ์คํธ ํ์: ์ด์ง ํ์์ ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ด์ผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ๊ฒ์(Comparison Search): ์์๋ค์ ๋น๊ตํ์ฌ ๊ฒ์ํฉ๋๋ค.
- ๋น ๋ฅธ ๊ฒ์ ์๋: ์๊ฐ ๋ณต์ก๋๊ฐ O(log n)์ผ๋ก, ์์์ ์๊ฐ ๋ง์๋ ๋น ๋ฅด๊ฒ ๊ฒ์ํ ์ ์์ต๋๋ค.
- ์ ์๋ฆฌ ๊ฒ์(In-place Search): ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ์ ๋ ฌ ํ์: ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ด์ผ๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๊ตฌํ ๋ณต์ก์ฑ: ์ ํ ๊ฒ์์ ๋นํด ๊ตฌํ์ด ์กฐ๊ธ ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
์ด์ง ํ์์ ๋ฐ๋ณต๋ฌธ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ ์ธ์๋ ์ฌ๊ท์ ์ผ๋ก ๊ตฌํํ ์ ์์ต๋๋ค. ๋ค์์ ์ฌ๊ท์ ์ด์ง ํ์์ ์์ ์ ๋๋ค.
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)์ ๊ฐ๋จํ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๋ก, ์ธ์ ํ ๋ ์์๋ฅผ ๋น๊ตํ์ฌ ํ์์ ๋ฐ๋ผ ์์น๋ฅผ ๋ฐ๊พธ๋ฉด์ ๋ฆฌ์คํธ๋ฅผ ์ ๋ ฌํ๋ ๋ฐฉ์์ ๋๋ค. ๋ฒ๋ธ ์ ๋ ฌ์ ์ด๋ฆ์ ๊ฐ์ฅ ํฐ ์์๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ๋ฆฌ์คํธ์ ๋์ผ๋ก "๋ถํ์ด ์ค๋ฅด๋" ๊ณผ์ ์์ ์ ๋๋์์ต๋๋ค.
๋ฒ๋ธ ์ ๋ ฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋น๊ต ๋ฐ ๊ตํ: ๋ฆฌ์คํธ์ ์ฒ์๋ถํฐ ์์ํ์ฌ ์ธ์ ํ ๋ ์์๋ฅผ ๋น๊ตํฉ๋๋ค. ๋ง์ฝ ์ฒซ ๋ฒ์งธ ์์๊ฐ ๋ ๋ฒ์งธ ์์๋ณด๋ค ํฌ๋ฉด ๋ ์์์ ์์น๋ฅผ ๋ฐ๊ฟ๋๋ค.
- ๋ฐ๋ณต: ๋ฆฌ์คํธ ๋๊น์ง ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค. ์ด ๊ณผ์ ์ ๋ฐ๋ณตํ๋ฉด ๊ฐ์ฅ ํฐ ์์๊ฐ ๋ฆฌ์คํธ์ ๋์ผ๋ก ์ด๋ํฉ๋๋ค.
- ๋ฐ๋ณต ๊ฐ์: ๋ฆฌ์คํธ ๋์ ๊ฐ์ฅ ํฐ ์์๊ฐ ๊ณ ์ ๋๋ฉด ๋ค์ ๋ฐ๋ณต์์๋ ๋ง์ง๋ง ์์๋ฅผ ์ ์ธํ ๋๋จธ์ง ์์๋ฅผ ๋น๊ตํฉ๋๋ค.
- ์ ๋ ฌ ์๋ฃ: ๋ ์ด์ ๊ตํ์ด ํ์ํ์ง ์์ ๋๊น์ง ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ ๋ฒ๋ธ ์ ๋ ฌ์ ์์ ์ ๋๋ค.
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 ]
๋ฒ๋ธ ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์
์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n^2)
- ๋ฆฌ์คํธ๊ฐ ์ญ์์ผ๋ก ์ ๋ ฌ๋ ๊ฒฝ์ฐ ๋ชจ๋ ์์๋ฅผ ๋น๊ตํ๊ณ ๊ตํํด์ผ ํฉ๋๋ค.
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(n^2)
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n)
- ๋ฆฌ์คํธ๊ฐ ์ด๋ฏธ ์ ๋ ฌ๋ ๊ฒฝ์ฐ ํ ๋ฒ์ ๋ฐ๋ณต๋ง์ผ๋ก ์ ๋ ฌ์ด ์๋ฃ๋ฉ๋๋ค.
- ๋จ์ํจ: ๋ฒ๋ธ ์ ๋ ฌ์ ๊ตฌํ์ด ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค.
- ์์ ์ฑ: ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ๋นํจ์จ์ฑ: ์๊ฐ ๋ณต์ก๋๊ฐ 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)์ ๋จ์ํ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๋ก, ๋ฆฌ์คํธ์์ ๊ฐ์ฅ ์์ ์์๋ฅผ ์ฐพ์ ๋งจ ์์ ์์์ ๊ตํํ๋ ๊ณผ์ ์ ๋ฐ๋ณตํ์ฌ ์ ๋ ฌํ๋ ๋ฐฉ์์ ๋๋ค. ์ ํ ์ ๋ ฌ์ ์ดํดํ๊ธฐ ์ฝ๊ณ ๊ตฌํ์ด ๊ฐ๋จํ์ง๋ง, ์๊ฐ ๋ณต์ก๋๊ฐ O(n^2)์ผ๋ก ๋นํจ์จ์ ์ ๋๋ค.
์ ํ ์ ๋ ฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์๊ฐ ์ฐพ๊ธฐ: ๋ฆฌ์คํธ์์ ํ์ฌ ์์น๋ถํฐ ๋๊น์ง ํ์ํ์ฌ ๊ฐ์ฅ ์์ ์์๋ฅผ ์ฐพ์ต๋๋ค.
- ๊ตํ: ๊ฐ์ฅ ์์ ์์๋ฅผ ํ์ฌ ์์น์ ์์์ ๊ตํํฉ๋๋ค.
- ๋ฐ๋ณต: ๋ฆฌ์คํธ์ ๋ชจ๋ ์์น์ ๋ํด ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ ์ ํ ์ ๋ ฌ์ ์์ ์ ๋๋ค.
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 ]
์ ํ ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์
์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n^2)
- ๋ชจ๋ ์์๋ฅผ ๋น๊ตํด์ผ ํ๋ฏ๋ก ๋ฐ๋ณต๋ฌธ์ด ์ค์ฒฉ๋์ด ์๊ฐ ๋ณต์ก๋๊ฐ O(n^2)์ ๋๋ค.
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(n^2)
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n^2)
- ์ด๋ฏธ ์ ๋ ฌ๋ ๋ฆฌ์คํธ์์๋ ๋ชจ๋ ์์๋ฅผ ๋น๊ตํ๋ฏ๋ก ์๊ฐ ๋ณต์ก๋๋ ์ฌ์ ํ O(n^2)์ ๋๋ค.
- ๋จ์ํจ: ์ ํ ์ ๋ ฌ์ ์ดํดํ๊ณ ๊ตฌํํ๊ธฐ ๋งค์ฐ ์ฝ์ต๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ(In-place Sort): ๋ณ๋์ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ, ์ฃผ์ด์ง ๋ฐฐ์ด ๋ด์์ ์ ๋ ฌ์ด ์ด๋ฃจ์ด์ง๋๋ค.
- ์์ ์ฑ: ์ ํ ์ ๋ ฌ์ ์์ ์ ์ด์ง ์์ต๋๋ค. ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํ์ง ์์ ์ ์์ต๋๋ค.
- ๋นํจ์จ์ฑ: ์๊ฐ ๋ณต์ก๋๊ฐ O(n^2)์ผ๋ก, ํฐ ๋ฆฌ์คํธ์ ๋ํด์๋ ๋นํจ์จ์ ์ ๋๋ค. ๋ฐ๋ผ์ ์ค์ ๋ก ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ๊ฐ ๋๋ญ ๋๋ค.
์ ํ ์ ๋ ฌ์ ๊ต์ก ๋ชฉ์ ์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๋ ๋จ์ํ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ดํดํ๊ธฐ ์ฝ๊ณ ๊ตฌํ์ด ๊ฐ๋จํ์ง๋ง, ์๊ฐ ๋ณต์ก๋ ์ธก๋ฉด์์ ๋นํจ์จ์ ์ด๋ฏ๋ก ์ค์ ๋ก๋ ํฌ๊ธฐ๊ฐ ์์ ๋ฐฐ์ด์ ์ ์ธํ๊ณ ๋ ์ ์ฌ์ฉ๋์ง ์์ต๋๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ, ํต ์ ๋ ฌ(Quick Sort), ๋ณํฉ ์ ๋ ฌ(Merge Sort), ํ ์ ๋ ฌ(Heap Sort)๊ณผ ๊ฐ์ ๋ ํจ์จ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ฝ์ ์ ๋ ฌ(Insertion Sort)์ ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๋ก, ๋ฐฐ์ด์ ๋ถ๋ถ์ ์ผ๋ก ์ ๋ ฌ๋ ์ํ๋ก ์ ์งํ๋ฉด์ ์๋ก์ด ์์๋ฅผ ์ฌ๋ฐ๋ฅธ ์์น์ ์ฝ์ ํ๋ ๋ฐฉ์์ ๋๋ค. ์ฝ์ ์ ๋ ฌ์ ์์ ๋ฐ์ดํฐ ์ธํธ์ ๋ํด์๋ ํจ์จ์ ์ด๊ณ , ๊ฑฐ์ ์ ๋ ฌ๋ ๋ฐฐ์ด์ ๋ํด์๋ ํจ์จ์ ์ ๋๋ค.
์ฝ์ ์ ๋ ฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋ถ๋ถ ์ ๋ ฌ ์ ์ง: ๋ฐฐ์ด์ ์ฒซ ๋ฒ์งธ ์์๋ ์ด๋ฏธ ์ ๋ ฌ๋ ์ํ๋ก ๊ฐ์ฃผํ๊ณ , ๋ ๋ฒ์งธ ์์๋ถํฐ ์์ํ์ฌ ๋ฐฐ์ด์ ๋ถ๋ถ์ ์ผ๋ก ์ ๋ ฌ๋ ์ํ๋ก ์ ์งํฉ๋๋ค.
- ์ฝ์ ์์น ์ฐพ๊ธฐ: ํ์ฌ ์์๋ฅผ ์ด๋ฏธ ์ ๋ ฌ๋ ๋ถ๋ถ ๋ฐฐ์ด๊ณผ ๋น๊ตํ์ฌ ์ ์ ํ ์์น๋ฅผ ์ฐพ์ต๋๋ค.
- ์ฝ์ : ํ์ฌ ์์๋ฅผ ์ฌ๋ฐ๋ฅธ ์์น์ ์ฝ์ ํฉ๋๋ค.
- ๋ฐ๋ณต: ๋ฐฐ์ด์ ๋ชจ๋ ์์์ ๋ํด ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ ์ฝ์ ์ ๋ ฌ์ ์์ ์ ๋๋ค.
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 ]
//
์ฝ์ ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์
์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n^2)
- ๋ฐฐ์ด์ด ์ญ์์ผ๋ก ์ ๋ ฌ๋ ๊ฒฝ์ฐ ๋ชจ๋ ์์๋ฅผ ๋น๊ตํ๊ณ ์ด๋ํด์ผ ํฉ๋๋ค.
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(n^2)
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n)
- ๋ฐฐ์ด์ด ์ด๋ฏธ ์ ๋ ฌ๋ ๊ฒฝ์ฐ ํ ๋ฒ์ ๋น๊ต๋ง์ผ๋ก ์ ๋ ฌ์ด ์๋ฃ๋ฉ๋๋ค.
- ๋จ์ํจ: ์ฝ์ ์ ๋ ฌ์ ์ดํดํ๊ณ ๊ตฌํํ๊ธฐ ๋งค์ฐ ์ฝ์ต๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ(In-place Sort): ๋ณ๋์ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ, ์ฃผ์ด์ง ๋ฐฐ์ด ๋ด์์ ์ ๋ ฌ์ด ์ด๋ฃจ์ด์ง๋๋ค.
- ์์ ์ฑ: ์ฝ์ ์ ๋ ฌ์ ์์ ์ ์ ๋๋ค. ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ํจ์จ์ฑ: ์ฝ์ ์ ๋ ฌ์ ์์ ๋ฐฐ์ด์ด๋ ๊ฑฐ์ ์ ๋ ฌ๋ ๋ฐฐ์ด์ ๋ํด์ ๋งค์ฐ ํจ์จ์ ์ ๋๋ค. ๊ทธ๋ฌ๋, ํฐ ๋ฐฐ์ด์ ๋ํด์๋ ๋นํจ์จ์ ์ ๋๋ค.
์ฝ์ ์ ๋ ฌ์ ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ์ดํดํ๊ธฐ ์ฝ๊ณ ๊ตฌํ์ด ๊ฐ๋จํฉ๋๋ค. ์์ ๋ฐ์ดํฐ ์ธํธ๋ ๊ฑฐ์ ์ ๋ ฌ๋ ๋ฐฐ์ด์ ๋ํด์๋ ๋งค์ฐ ํจ์จ์ ์ด๋ฉฐ, ์์ ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๊ทธ๋ฌ๋, ์๊ฐ ๋ณต์ก๋๊ฐ O(n^2)์ด๊ธฐ ๋๋ฌธ์ ํฐ ๋ฐฐ์ด์ ๋ํด์๋ ๋นํจ์จ์ ์ด๋ฉฐ, ์ด ๊ฒฝ์ฐ ํต ์ ๋ ฌ(Quick Sort), ๋ณํฉ ์ ๋ ฌ(Merge Sort), ํ ์ ๋ ฌ(Heap Sort)๊ณผ ๊ฐ์ ๋ ํจ์จ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ณํฉ ์ ๋ ฌ(Merge Sort)์ Divide and Conquer ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ ํจ์จ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๋ณํฉ ์ ๋ ฌ์ ๋ฆฌ์คํธ๋ฅผ ๋ฐ์ผ๋ก ๋๋์ด ๊ฐ๊ฐ์ ์ฌ๊ท์ ์ผ๋ก ์ ๋ ฌํ๊ณ , ์ ๋ ฌ๋ ๋ถ๋ถ ๋ฆฌ์คํธ๋ฅผ ํฉ์ณ์ ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ์ ๋ ฌํฉ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ์์ ์ ์ด๊ณ , ์๊ฐ ๋ณต์ก๋๊ฐ O(n log n)์ผ๋ก ๋งค์ฐ ํจ์จ์ ์ ๋๋ค.
๋ณํฉ ์ ๋ ฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ๋ถํ (Divide): ๋ฆฌ์คํธ๋ฅผ ๋ ๊ฐ์ ํ์ ๋ฆฌ์คํธ๋ก ๋๋๋๋ค.
- ์ ๋ณต(Conquer): ํ์ ๋ฆฌ์คํธ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋ณํฉ ์ ๋ ฌํฉ๋๋ค.
- ๊ฒฐํฉ(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 ]
๋ณํฉ ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์
์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n log n)
- ๋ฆฌ์คํธ๋ฅผ ๊ณ์ํด์ ๋ฐ์ผ๋ก ๋๋๊ณ , ๊ฐ ๋จ๊ณ์์ ๋ณํฉํ๋ ๋ฐ O(n) ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(n log n)
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n log n)
- ์์ ์ฑ: ๋ณํฉ ์ ๋ ฌ์ ์์ ์ ์ ๋๋ค. ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ์ด ์๋(Not In-place Sort): ๋ณํฉ ์ ๋ ฌ์ ์ถ๊ฐ์ ์ธ ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ๋ณํฉ ๊ณผ์ ์ ์ํํ๊ธฐ ๋๋ฌธ์, ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
- ๋ถํ ์ ๋ณต ๊ธฐ๋ฒ(Divide and Conquer): ๋ฆฌ์คํธ๋ฅผ ๋ถํ ํ๊ณ , ๊ฐ๊ฐ์ ์ ๋ ฌํ ํ ๋ณํฉํ์ฌ ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ์ ๋ ฌํฉ๋๋ค.
- ์์ ์ ์ธ ์ ๋ ฌ: ์ ๋ ฅ ๋ฐ์ดํฐ์ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ์์ธก ๊ฐ๋ฅํ ์๊ฐ ๋ณต์ก๋: ์ต์ , ํ๊ท , ์ต์ ์ ๊ฒฝ์ฐ ๋ชจ๋ O(n log n)์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋๋ค.
- ์ธ๋ถ ์ ๋ ฌ ๊ฐ๋ฅ: ํฐ ๋ฐ์ดํฐ๋ฅผ ๋์คํฌ์์ ์ ๋ ฌํ ๋ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
- ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ: ๋ณํฉ ์ ๋ ฌ์ ์ถ๊ฐ์ ์ธ ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ๋ณํฉ์ ์ํํ๋ฏ๋ก, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋์ด๋ฉ๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ: ๋ฐ์ดํฐ์ ํฌ๊ธฐ์ ๋ฐ๋ผ ๋น๊ต ์ฐ์ฐ์ด ๋ง์ด ํ์ํ ์ ์์ต๋๋ค.
๋ณํฉ ์ ๋ ฌ์ ํจ์จ์ ์ด๊ณ ์์ ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ํนํ ํฐ ๋ฐ์ดํฐ ์ธํธ๋ ์ธ๋ถ ์ ๋ ฌ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ์ฉํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ด ํ์ํ๋ค๋ ๋จ์ ์ด ์์ผ๋ฏ๋ก, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ด ์ค์ํ ํ๊ฒฝ์์๋ ํต ์ ๋ ฌ(Quick Sort)๊ณผ ๊ฐ์ ๋ค๋ฅธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๊ณ ๋ คํ ์ ์์ต๋๋ค.
ํต ์ ๋ ฌ(Quick Sort)์ Divide and Conquer ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ ๋งค์ฐ ํจ์จ์ ์ธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ํ๊ท ์ ์ผ๋ก ๋งค์ฐ ๋น ๋ฅธ ์๊ฐ ๋ณต์ก๋์ธ O(n log n)์ ๊ฐ์ง๋ฉฐ, ์ ์๋ฆฌ ์ ๋ ฌ(In-place Sort) ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ํต ์ ๋ ฌ์ ๋ฆฌ์คํธ์์ ํผ๋ฒ(pivot) ์์๋ฅผ ์ ํํ๊ณ , ์ด๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ๋ ๊ฐ์ ํ์ ๋ฆฌ์คํธ๋ก ๋๋๋ ๊ณผ์ ์ ๋ฐ๋ณตํ์ฌ ์ ๋ ฌํฉ๋๋ค.
ํต ์ ๋ ฌ์ ๊ธฐ๋ณธ ๊ฐ๋ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ํผ๋ฒ ์ ํ: ๋ฆฌ์คํธ์์ ํผ๋ฒ ์์๋ฅผ ์ ํํฉ๋๋ค.
- ๋ถํ : ํผ๋ฒ์ ๊ธฐ์ค์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ๋ ๊ฐ์ ํ์ ๋ฆฌ์คํธ๋ก ๋ถํ ํฉ๋๋ค. ํผ๋ฒ๋ณด๋ค ์์ ์์๋ค์ ํผ๋ฒ์ ์ผ์ชฝ์ผ๋ก, ํผ๋ฒ๋ณด๋ค ํฐ ์์๋ค์ ํผ๋ฒ์ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ํฉ๋๋ค.
- ์ฌ๊ท ํธ์ถ: ๋ถํ ๋ ํ์ ๋ฆฌ์คํธ์ ๋ํด ํต ์ ๋ ฌ์ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํฉ๋๋ค.
- ๊ฒฐํฉ: ํ์ ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋๋ฉด ์ด๋ค์ ๊ฒฐํฉํ์ฌ ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ์ ๋ ฌํฉ๋๋ค.
๋ค์์ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ ํต ์ ๋ ฌ์ ์์ ์ ๋๋ค.
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;
}
ํต ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์
์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n^2)
- ๋ฆฌ์คํธ๊ฐ ์ด๋ฏธ ์ ๋ ฌ๋ ๊ฒฝ์ฐ๋ ํผ๋ฒ์ด ์ต์๊ฐ์ด๋ ์ต๋๊ฐ์ผ๋ก ์ ํ๋๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(n log n)
- ๋ฆฌ์คํธ๊ฐ ๊ท ๋ฑํ๊ฒ ๋ถํ ๋๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(n log n)
- ํผ๋ฒ์ด ํญ์ ๋ฆฌ์คํธ์ ์ค์๊ฐ์ ์ ํํ์ฌ ๊ท ๋ฑํ๊ฒ ๋ถํ ๋๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ(In-place Sort): ํต ์ ๋ ฌ์ ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฑฐ์ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ(Comparison Sort): ์์๋ค์ ๋น๊ตํ์ฌ ์ ๋ ฌํฉ๋๋ค.
- ๋ถ์์ ์ ๋ ฌ(Unstable Sort): ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํ์ง ์์ ์ ์์ต๋๋ค.
ํต ์ ๋ ฌ์ ํ๊ท ์ ์ผ๋ก ๋งค์ฐ ๋น ๋ฅธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก, ๋๋ถ๋ถ์ ์ค์ฉ์ ์ธ ์ ๋ ฌ ์์ ์ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ ์๋ฆฌ ์ ๋ ฌ์ด ๊ฐ๋ฅํ๊ณ , ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ด ์ ์ด ํจ์จ์ ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋๊ฐ O(n^2)์ผ ์ ์์ผ๋ฏ๋ก, ํผ๋ฒ ์ ํ ์ต์ ํ์ ๊ฐ์ ๋ค์ํ ์ต์ ํ ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
Radix Sort(๊ธฐ์ ์ ๋ ฌ)์ ์ ์๋ ๋ฌธ์์ด์ ์๋ฆฟ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํ๋ ํจ์จ์ ์ธ ์ ์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ์ฃผ๋ก ์์ ์ ์๋ ๊ณ ์ ๊ธธ์ด์ ๋ฌธ์์ด์ ์ ๋ ฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ์๊ฐ ๋ณต์ก๋๊ฐ O(d * (n + k))๋ก, ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ๋ณด๋ค ๋ ํจ์จ์ ์ผ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์ d๋ ๋ฐ์ดํฐ์ ์ต๋ ์๋ฆฟ์, n์ ์์์ ์, k๋ ๊ธฐ์(์: 10์ง๋ฒ์์๋ 10)์ ๋๋ค.
๊ธฐ์ ์ ๋ ฌ์ LSD(Least Significant Digit)์ MSD(Most Significant Digit) ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๋๋ฉ๋๋ค:
- LSD ๋ฐฉ์: ๊ฐ์ฅ ์์ ์๋ฆฟ์๋ถํฐ ์์ํ์ฌ ํฐ ์๋ฆฟ์ ๋ฐฉํฅ์ผ๋ก ์ ๋ ฌํฉ๋๋ค.
- MSD ๋ฐฉ์: ๊ฐ์ฅ ํฐ ์๋ฆฟ์๋ถํฐ ์์ํ์ฌ ์์ ์๋ฆฟ์ ๋ฐฉํฅ์ผ๋ก ์ ๋ ฌํฉ๋๋ค.
LSD ๋ฐฉ์์ ์ผ๋ฐ์ ์ผ๋ก ๋ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
- ์ต๋ ์๋ฆฟ์ ๊ฒฐ์ : ๋ฐ์ดํฐ ์ค ๊ฐ์ฅ ํฐ ์์ ์๋ฆฟ์๋ฅผ ๊ตฌํฉ๋๋ค.
- ์๋ฆฟ์๋ณ ์ ๋ ฌ: ๊ฐ ์๋ฆฟ์์ ๋ํด ์ ๋ ฌ์ ์ํํฉ๋๋ค. ์ด๋, ์์ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ(์: 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]
๊ธฐ์ ์ ๋ ฌ์ ์๊ฐ ๋ณต์ก๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(d * (n + k))
- ํ๊ท ์๊ฐ ๋ณต์ก๋: O(d * (n + k))
- ์ต์ ์ ๊ฒฝ์ฐ ์๊ฐ ๋ณต์ก๋: O(d * (n + k))
์ฌ๊ธฐ์ d๋ ๋ฐ์ดํฐ์ ์ต๋ ์๋ฆฟ์, n์ ์์์ ์, k๋ ๊ธฐ์(์: 10์ง๋ฒ์์๋ 10)์ ๋๋ค.
- ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ์ด ์๋: ์์๋ค์ ๋น๊ตํ์ง ์๊ณ ์๋ฆฟ์๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌํฉ๋๋ค.
- ์์ ์ ๋ ฌ: ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ์ด ์๋: ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ด ํ์ํฉ๋๋ค.
- ํจ์จ์ฑ: ํน์ ์กฐ๊ฑด์์ ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ๋ณด๋ค ํจ์จ์ ์ผ ์ ์์ต๋๋ค.
- ์์ ์ฑ: ๋์ผํ ๊ฐ์ ์์๋ค์ด ์ ๋ ฅ ์์๋ฅผ ์ ์งํฉ๋๋ค.
- ์ ์๋ฆฌ ์ ๋ ฌ ์๋: ์ถ๊ฐ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ด ํ์ํฉ๋๋ค.
- ๋ฐ์ดํฐ ํ์ ์ ํ: ์ฃผ๋ก ์ ์๋ ๊ณ ์ ๊ธธ์ด ๋ฌธ์์ด์๋ง ์ ์ฉํ ์ ์์ต๋๋ค.
- ์๋ฆฟ์์ ๋ฏผ๊ฐ: ๋ฐ์ดํฐ์ ์๋ฆฟ์๊ฐ ๋ง์ ๊ฒฝ์ฐ ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ์์ต๋๋ค.
๊ธฐ์ ์ ๋ ฌ์ ์ ์๋ ๊ณ ์ ๊ธธ์ด ๋ฌธ์์ด์ ์ ๋ ฌํ๋ ๋ฐ ๋งค์ฐ ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ๋น๊ต ๊ธฐ๋ฐ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๋นํด ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ผ ์ ์์ง๋ง, ๋ฐ์ดํฐ ํ์ ๊ณผ ์๋ฆฟ์์ ์ ํ์ด ์์ต๋๋ค. ํฐ ๋ฐ์ดํฐ์ ์ด๋ ์๋ฆฟ์๊ฐ ๋ง์ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ, ๊ธฐ์ ์ ๋ ฌ์ ์ฑ๋ฅ์ด ๋จ์ด์ง ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ ๋ค๋ฅธ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๋ณํํ์ฌ ์ฌ์ฉํ๊ฑฐ๋, ์ํฉ์ ๋ง๋ ์๊ณ ๋ฆฌ์ฆ์ ์ ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
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);
- ๋ฉ๋ชจ๋ฆฌ ํ ๋น ๋ฐฉ์:
- ๋ฐฐ์ด: ์ฐ์๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์์๋ค์ด ์ ์ฅ๋ฉ๋๋ค. ์ธ๋ฑ์ค๋ฅผ ํตํด ๋น ๋ฅด๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.
- ๋งํฌ๋ ๋ฆฌ์คํธ: ์์๋ค์ด ๋ถ์ฐ์์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ ์ฅ๋ฉ๋๋ค. ๊ฐ ์์๋ ํฌ์ธํฐ๋ฅผ ํตํด ์ฐ๊ฒฐ๋ฉ๋๋ค.
- ์ ๊ทผ ์๊ฐ:
- ๋ฐฐ์ด: ์ธ๋ฑ์ค๋ฅผ ํตํด O(1) ์๊ฐ ๋ณต์ก๋๋ก ์์์ ์์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
- ๋งํฌ๋ ๋ฆฌ์คํธ: ํน์ ์์์ ์ ๊ทผํ๋ ค๋ฉด ์ฒซ ๋ฒ์งธ ๋ ธ๋๋ถํฐ ์์ฐจ์ ์ผ๋ก ํ์ํด์ผ ํ๋ฏ๋ก, ํ๊ท ์ ์ผ๋ก O(n) ์๊ฐ ๋ณต์ก๋๊ฐ ์์๋ฉ๋๋ค.
- ์ฝ์
๋ฐ ์ญ์ :
- ๋ฐฐ์ด: ํน์ ์์น์ ์์๋ฅผ ์ฝ์ ํ๊ฑฐ๋ ์ญ์ ํ๋ ค๋ฉด ์์๋ค์ ์ด๋ํด์ผ ํ๋ฏ๋ก, ํ๊ท ์ ์ผ๋ก O(n) ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
- ๋งํฌ๋ ๋ฆฌ์คํธ: ํน์ ์์น์ ์์๋ฅผ ์ฝ์ ํ๊ฑฐ๋ ์ญ์ ํ ๋ ์์๋ค์ ์ด๋ํ ํ์๊ฐ ์์ผ๋ฏ๋ก, ์ฝ์ ๊ณผ ์ญ์ ๋ O(1) ์๊ฐ ๋ณต์ก๋๋ก ์ํ๋ฉ๋๋ค. ๋จ, ์ฝ์ ๋๋ ์ญ์ ํ ์์น๋ฅผ ์ฐพ๊ธฐ ์ํด O(n) ์๊ฐ์ด ์์๋ ์ ์์ต๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ:
- ๋ฐฐ์ด: ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ์ง๋ง, ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ ๋๋ ์๋ก์ด ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ด ํ์ํ ์ ์์ต๋๋ค.
- ๋งํฌ๋ ๋ฆฌ์คํธ: ๊ฐ ์์๋ง๋ค ์ถ๊ฐ์ ์ธ ํฌ์ธํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํ๋ฏ๋ก, ๋ฐฐ์ด๋ณด๋ค ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ง์ ์ ์์ต๋๋ค.
- ์ฐ๊ฒฐ์ฑ:
- ๋ฐฐ์ด: ๊ณ ์ ๋ ํฌ๊ธฐ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก, ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ๋ ค๋ฉด ์๋ก์ด ๋ฐฐ์ด์ ํ ๋นํ๊ณ ๊ธฐ์กด ์์๋ค์ ๋ณต์ฌํด์ผ ํฉ๋๋ค.
- ๋งํฌ๋ ๋ฆฌ์คํธ: ๋์ ์ผ๋ก ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์์ผ๋ฉฐ, ๋ ธ๋๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ๋ ๊ฒ์ด ์๋์ ์ผ๋ก ๊ฐ๋จํฉ๋๋ค.
๋งํฌ๋ ๋ฆฌ์คํธ์ ๋ฐฐ์ด์ ๊ฐ๊ธฐ ๋ค๋ฅธ ์ฅ์ ๊ณผ ๋จ์ ์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ฌ์ฉ ๋ชฉ์ ์ ๋ฐ๋ผ ์ ์ ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ฐฐ์ด์ ๋น ๋ฅธ ์ ๊ทผ ์๊ฐ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ ํฉํ๊ณ , ๋งํฌ๋ ๋ฆฌ์คํธ๋ ๋น๋ฒํ ์ฝ์ ๊ณผ ์ญ์ ๊ฐ ํ์ํ ๊ฒฝ์ฐ์ ์ ๋ฆฌํฉ๋๋ค.
๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ(Doubly Linked List)๋ ๊ฐ ๋ ธ๋๊ฐ ๋ ๊ฐ์ ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๋ ๋งํฌ๋ ๋ฆฌ์คํธ์ ๋๋ค. ํ๋๋ ๋ค์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๊ณ , ๋ค๋ฅธ ํ๋๋ ์ด์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํต๋๋ค. ์ด๋ฅผ ํตํด ๋ฆฌ์คํธ์ ์๋ฐฉํฅ ํ์์ด ๊ฐ๋ฅํด์ง๋๋ค.
- ๋
ธ๋ ๊ตฌ์กฐ(Node Structure): ๊ฐ ๋
ธ๋๋ data, next, prev ์ธ ๊ฐ์ง ์์ฑ์ ๊ฐ์ง๋๋ค.
- data: ๋ ธ๋๊ฐ ์ ์ฅํ๋ ๋ฐ์ดํฐ
- next: ๋ค์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
- prev: ์ด์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
- ๋ฆฌ์คํธ์ ๊ตฌ์กฐ(List Structure): ๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ๋ head์ tail ๋ ๊ฐ์ ํฌ์ธํฐ๋ฅผ ๊ฐ์ง๋๋ค.
- head: ๋ฆฌ์คํธ์ ์ฒซ ๋ฒ์งธ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํด
- tail: ๋ฆฌ์คํธ์ ๋ง์ง๋ง ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํด
- ์๋ฐฉํฅ ํ์: ์๋ฐฉํฅ์ผ๋ก ํ์์ด ๊ฐ๋ฅํ์ฌ, ์๋ค๋ก ์ด๋ํ๋ฉฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์ถ๊ฐ (Insertion):
- ๋ฆฌ์คํธ์ ์์ ์ถ๊ฐ: unshift
- ๋ฆฌ์คํธ์ ๋์ ์ถ๊ฐ: push
- ๋ฆฌ์คํธ์ ์ค๊ฐ์ ์ถ๊ฐ: insert
- ์ ๊ฑฐ (Removal):
- ๋ฆฌ์คํธ์ ์์์ ์ ๊ฑฐ: shift
- ๋ฆฌ์คํธ์ ๋์์ ์ ๊ฑฐ: pop
- ๋ฆฌ์คํธ์ ์ค๊ฐ์์ ์ ๊ฑฐ: remove
- ํ์ (Traversal):
- ์ธ๋ฑ์ค๋ฅผ ์ด์ฉํ ๋ ธ๋ ํ์: get
๋ค์์ ๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ์ ๊ฐ๋จํ ๊ตฌํ์ ๋๋ค.
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;
}
}
}
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ: ๋งํฌ๋ ๋ฆฌ์คํธ๋ ๋ ธ๋๋น ์ถ๊ฐ์ ์ธ ํฌ์ธํฐ(next, prev)๋ฅผ ์ ์ฅํด์ผ ํ๋ฏ๋ก ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ด ๋ฐฐ์ด๋ณด๋ค ํฝ๋๋ค.
- ์ ๊ทผ ์๊ฐ: ๋ฐฐ์ด์ ์ธ๋ฑ์ค๋ฅผ ํตํด O(1) ์๊ฐ์ ์์์ ์ ๊ทผํ ์ ์์ง๋ง, ๋งํฌ๋ ๋ฆฌ์คํธ๋ O(n) ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
- ์ฝ์ /์ญ์ ์๊ฐ: ๋ฐฐ์ด์ ์ค๊ฐ์ ์ฝ์ ํ๊ฑฐ๋ ์ญ์ ํ ๋ O(n) ์๊ฐ์ด ๊ฑธ๋ฆฌ์ง๋ง, ๋งํฌ๋ ๋ฆฌ์คํธ๋ ํด๋น ์์น๋ฅผ ์ฐพ๋ ์๊ฐ(O(n)) ์ธ์๋ O(1) ์๊ฐ์ ๊ฐ๋ฅํฉ๋๋ค.
๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ๋ ์๋ฐฉํฅ ํ์์ด ๊ฐ๋ฅํ๋ค๋ ์ฅ์ ์ด ์์ด, ์ฝ์ ๊ณผ ์ญ์ ๊ฐ ๋น๋ฒํ ๊ฒฝ์ฐ ์ ๋ฆฌํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ฐฐ์ด์ ๋นํด ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋ง๊ณ , ์์ ์ ๊ทผ์ด ๋๋ฆฌ๋ค๋ ๋จ์ ๋ ์์ต๋๋ค.
์คํ(Stack)์ ํ์ ์ ์ถ(LIFO, Last In First Out) ์์น์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ์๋ฃ ๊ตฌ์กฐ์ ๋๋ค. ์ด๋ ๋ง์ง๋ง์ ์ฝ์ ๋ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ฅ ๋จผ์ ์ ๊ฑฐ๋๋ ๊ตฌ์กฐ๋ฅผ ์๋ฏธํฉ๋๋ค. ์คํ์ ์ฃผ๋ก ์ฌ๊ท ์๊ณ ๋ฆฌ์ฆ, ์ธ์ด์ ํจ์ ํธ์ถ, ์คํ ์ทจ์ ๊ธฐ๋ฅ ๋ฑ์์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
- push: ์คํ์ ๋งจ ์์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- pop: ์คํ์ ๋งจ ์์ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ๊ณ ๋ฐํํฉ๋๋ค.
- peek (๋๋ top): ์คํ์ ๋งจ ์์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ์ง๋ง ์ ๊ฑฐํ์ง๋ ์์ต๋๋ค.
- isEmpty: ์คํ์ด ๋น์ด ์๋์ง ํ์ธํฉ๋๋ค.
- size: ์คํ์ ์๋ ๋ฐ์ดํฐ์ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
- LIFO: ๋ง์ง๋ง์ ์ฝ์ ๋ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ฅ ๋จผ์ ์ ๊ฑฐ๋ฉ๋๋ค.
- ์ ํ๋ ์ ๊ทผ: ์คํ์ ์ค์ง ํ์ชฝ ๋์์๋ง ๋ฐ์ดํฐ์ ์ฝ์ ๊ณผ ์ ๊ฑฐ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- ์ฌ๊ท ์๊ณ ๋ฆฌ์ฆ: ํจ์ ํธ์ถ ์ ํธ์ถ๋ ํจ์๊ฐ ์๋ฃ๋ ๋๊น์ง์ ์ํ๋ฅผ ์ ์ฅํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
- ์น ๋ธ๋ผ์ฐ์ ์ ๋ค๋ก ๊ฐ๊ธฐ ๊ธฐ๋ฅ: ์ฌ์ฉ์๊ฐ ๋ฐฉ๋ฌธํ ํ์ด์ง๋ฅผ ์คํ์ ์ ์ฅํ๊ณ , ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ์คํ์ ๋งจ ์ ํ์ด์ง๋ฅผ ์ ๊ฑฐํ๊ณ ์ด์ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค.
- ํ ์คํธ ํธ์ง๊ธฐ์ ์คํ ์ทจ์ ๊ธฐ๋ฅ: ์ฌ์ฉ์๊ฐ ์ํํ ์์ ์ ์คํ์ ์ ์ฅํ๊ณ , ์คํ ์ทจ์ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋ง์ง๋ง ์์ ์ ์ ๊ฑฐํ์ฌ ์ด์ ์ํ๋ก ๋๋๋ฆฝ๋๋ค.
๋ค์์ 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
- ์ ๊ทผ ๋ฐฉ์: ์คํ์ LIFO ๊ตฌ์กฐ๋ก ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ ๋ฐ๋ฉด, ๋ฐฐ์ด์ ์ธ๋ฑ์ค๋ฅผ ํตํด ์์ ์ ๊ทผ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ์ฐ์ฐ ์๊ฐ ๋ณต์ก๋: ์คํ์ push์ pop ์ฐ์ฐ์ O(1) ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋๋ค. ๋ฐฐ์ด์์๋ ๋์ ์์๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ๊ฑฐํ๋ ๊ฒ์ O(1)์ด์ง๋ง, ๋ฐฐ์ด์ ์ค๊ฐ์ ์์๋ฅผ ์ฝ์ ํ๊ฑฐ๋ ์ ๊ฑฐํ๋ ๊ฒ์ O(n)์ ๋๋ค.
์คํ์ ๋จ์ํ ๊ตฌ์กฐ์์๋ ๋ถ๊ตฌํ๊ณ ๋ค์ํ ์๊ณ ๋ฆฌ์ฆ๊ณผ ํ๋ก๊ทธ๋จ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค. ํนํ ์ฌ๊ท์ ๋ฌธ์ ํด๊ฒฐ, ์คํ ์ทจ์ ๊ธฐ๋ฅ, ํจ์ ํธ์ถ ๊ด๋ฆฌ ๋ฑ์์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
ํ(Queue)๋ ์๋ฃ ๊ตฌ์กฐ์ ํ ํํ๋ก, ์ ์ ์ ์ถ(FIFO, First In First Out) ์์น์ ๋ฐ๋ฆ ๋๋ค. ์ฆ, ๋จผ์ ์ฝ์ ๋ ๋ฐ์ดํฐ๊ฐ ๋จผ์ ์ญ์ ๋ฉ๋๋ค. ํ๋ ์ผ์ ์ํ์ ์ค ์๊ธฐ์ ์ ์ฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ๋๋ค์ด ์ค์ ์์ ๋๊ธฐํ๋ ๊ฒฝ์ฐ, ์ค์ ๋งจ ์์ ์๋ ์ฌ๋์ด ๊ฐ์ฅ ๋จผ์ ์๋น์ค๋ฐ๊ณ ์ค์์ ๋๊ฐ๋ฉฐ, ์๋ก์ด ์ฌ๋์ ์ค์ ๋งจ ๋ค์ ์๊ฒ ๋ฉ๋๋ค.
- enqueue: ํ์ ๋งจ ๋ค์ ์์๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- dequeue: ํ์ ๋งจ ์์์ ์์๋ฅผ ์ ๊ฑฐํ๊ณ ๋ฐํํฉ๋๋ค.
- peek/front: ํ์ ๋งจ ์ ์์๋ฅผ ๋ฐํํ์ง๋ง, ์ ๊ฑฐํ์ง๋ ์์ต๋๋ค.
- isEmpty: ํ๊ฐ ๋น์ด ์๋์ง ํ์ธํฉ๋๋ค.
- 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, BST)๋ ๋ฐ์ดํฐ์ ํจ์จ์ ์ธ ์ ์ฅ, ๊ฒ์, ์ฝ์ ๋ฐ ์ญ์ ๋ฅผ ์ํด ์ฌ์ฉ๋๋ ํธ๋ฆฌ ๊ตฌ์กฐ์ ๋๋ค. ๊ฐ ๋ ธ๋๊ฐ ์ต๋ ๋ ๊ฐ์ ์์ ๋ ธ๋๋ฅผ ๊ฐ์ง๋ฉฐ, ์ผ์ชฝ ์์ ๋ ธ๋์ ๊ฐ์ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ๋ณด๋ค ์๊ณ , ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋์ ๊ฐ์ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ๋ณด๋ค ํฝ๋๋ค. ์ด๋ฌํ ํน์ฑ ๋๋ถ์ ์ด์ง ํ์ ํธ๋ฆฌ๋ ์ ๋ ฌ๋ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ๋ชจ๋ ๋ ธ๋์ ๊ฐ์ ์ ์ผํฉ๋๋ค.
- ์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ชจ๋ ๋ ธ๋ ๊ฐ์ ๋ถ๋ชจ ๋ ธ๋ ๊ฐ๋ณด๋ค ์์ต๋๋ค.
- ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ชจ๋ ๋ ธ๋ ๊ฐ์ ๋ถ๋ชจ ๋ ธ๋ ๊ฐ๋ณด๋ค ํฝ๋๋ค.
- ์ผ์ชฝ ๋ฐ ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ๋ ๊ฐ๊ฐ ์ด์ง ํ์ ํธ๋ฆฌ์ ๋๋ค.
- ์ฝ์ (Insert): ์๋ก์ด ๊ฐ์ ์ฌ๋ฐ๋ฅธ ์์น์ ์ถ๊ฐํฉ๋๋ค.
- ๊ฒ์ (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));
- Node ํด๋์ค:
- value: ๋ ธ๋์ ๊ฐ.
- left: ์ผ์ชฝ ์์ ๋ ธ๋.
- right: ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋.
- BinarySearchTree ํด๋์ค:
- root: ํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋.
- insert(value):
- ์ ๋ ธ๋๋ฅผ ์์ฑํ๊ณ ์ฌ๋ฐ๋ฅธ ์์น์ ์ฝ์ ํฉ๋๋ค.
- ๋ฃจํธ ๋ ธ๋๊ฐ ์์ผ๋ฉด ์ ๋ ธ๋๋ฅผ ๋ฃจํธ๋ก ์ค์ ํฉ๋๋ค.
- ๋ฃจํธ ๋ ธ๋๊ฐ ์์ผ๋ฉด ๊ฐ์ ๋น๊ตํ์ฌ ์ผ์ชฝ ๋๋ ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋๋ก ์ด๋ํ๋ฉด์ ์ฝ์ ์์น๋ฅผ ์ฐพ์ต๋๋ค.
- search(value):
- ํธ๋ฆฌ์์ ํน์ ๊ฐ์ ๊ฐ์ง ๋ ธ๋๋ฅผ ์ฐพ์ต๋๋ค.
- ๋ฃจํธ ๋ ธ๋๋ถํฐ ์์ํ์ฌ ๊ฐ์ ๋น๊ตํ๋ฉด์ ์ผ์ชฝ ๋๋ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋ํฉ๋๋ค.
์ด์ง ํ์ ํธ๋ฆฌ๋ ์ฝ์ , ์ญ์ , ๊ฒ์ ์ฐ์ฐ์ด ํ๊ท ์ ์ผ๋ก O(log n) ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋ฉฐ, ์ต์ ์ ๊ฒฝ์ฐ(ํธํฅ ํธ๋ฆฌ)์๋ O(n) ์๊ฐ ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋๋ค. ๊ท ํ ์กํ ํธ๋ฆฌ๋ฅผ ์ ์งํ๊ธฐ ์ํด AVL ํธ๋ฆฌ, ๋ ๋-๋ธ๋ ํธ๋ฆฌ์ ๊ฐ์ ๋ณํ ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋๋น ์ฐ์ ํ์(Breadth-First Search, BFS)์ ๊ทธ๋ํ ๋๋ ํธ๋ฆฌ์ ๋ ธ๋๋ฅผ ํ์ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋์ ๋๋ค. BFS๋ ์์ ๋ ธ๋์์ ์ถ๋ฐํ์ฌ ์ธ์ ํ ๋ ธ๋๋ฅผ ๋จผ์ ํ์ํ๊ณ , ๊ทธ ๋ค์ ์ธ์ ํ ๋ ธ๋๋ค์ ์ธ์ ๋ ธ๋๋ฅผ ํ์ํ๋ ๋ฐฉ์์ผ๋ก ์งํ๋ฉ๋๋ค. ์ด๋ ์ฃผ๋ก ํ(queue) ์๋ฃ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํ๋ฉ๋๋ค.
- ๋ ๋ฒจ๋ณ ํ์: BFS๋ ํธ๋ฆฌ ๋๋ ๊ทธ๋ํ์ ๋ ๋ฒจ์ ๊ธฐ์ค์ผ๋ก ๋ ธ๋๋ฅผ ํ์ํฉ๋๋ค. ์ฆ, ์ฒซ ๋ฒ์งธ ๋ ๋ฒจ(๋ฃจํธ ๋ ธ๋)์์ ์์ํ์ฌ ๋ค์ ๋ ๋ฒจ๋ก ์งํํฉ๋๋ค.
- ์ต๋จ ๊ฒฝ๋ก ํ์: ๋ฌด๋ฐฉํฅ ๊ทธ๋ํ์์ BFS๋ ์์ ๋ ธ๋์์ ๋ค๋ฅธ ๋ ธ๋๋ก ๊ฐ๋ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
- ํ ์ฌ์ฉ: BFS๋ FIFO(First In, First Out) ํน์ฑ์ ๊ฐ์ง ํ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์์ ํ์ํ ๋ ธ๋๋ฅผ ๊ด๋ฆฌํฉ๋๋ค.
ํธ๋ฆฌ์ ๊ทธ๋ํ๋ฅผ ์ํ 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์ ์๊ฐ ๋ณต์ก๋๋ ๊ทธ๋ํ์ ๋ ธ๋ ์(V)์ ์ฃ์ง ์(E)์ ๋ฐ๋ผ O(V + E)์ ๋๋ค. ์ด๋ ๋ชจ๋ ๋ ธ๋์ ์ฃ์ง๋ฅผ ํ ๋ฒ์ฉ ๋ฐฉ๋ฌธํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํธ๋ฆฌ์ ๊ฒฝ์ฐ ๋ ธ๋ ์๊ฐ n์ผ ๋, ์๊ฐ ๋ณต์ก๋๋ O(n)์ ๋๋ค.
BFS๋ ๋๋น ์ฐ์ ์ผ๋ก ํ์ํ์ฌ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ๋ ๋ฌธ์ ์ ์ ํฉํ๋ฉฐ, ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ์์ ํ ํ์ํด์ผ ํ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
๊น์ด ์ฐ์ ํ์(Depth-First Search, DFS)์ ๊ทธ๋ํ ๋๋ ํธ๋ฆฌ์ ๋ ธ๋๋ฅผ ํ์ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ก, ๊ฐ๋ฅํ ํ ๊น์ด ์๋ ๋ ธ๋๋ฅผ ์ฐ์ ์ผ๋ก ํ์ํฉ๋๋ค. DFS๋ ์คํ(stack) ์๋ฃ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ ์ ์์ผ๋ฉฐ, ์ฌ๊ท์ ์ผ๋ก๋ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
- ๊น์ด ์ฐ์ ํ์: ๊ฐ๋ฅํ ํ ๊น์ด ์๋ ๋ ธ๋๋ฅผ ๋จผ์ ํ์ํ๊ณ , ๋ ์ด์ ๊น์ด ๊ฐ ์ ์์ ๋ ๋ค์ ์ธ์ ํ ๋ ธ๋๋ก ์ด๋ํฉ๋๋ค.
- ์คํ ์ฌ์ฉ: DFS๋ LIFO(Last In, First Out) ํน์ฑ์ ๊ฐ์ง ์คํ์ ์ฌ์ฉํ์ฌ ๋ค์์ ํ์ํ ๋ ธ๋๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ์ฌ๊ท์ ๊ตฌํ์์๋ ํจ์ ํธ์ถ ์คํ์ ์ฌ์ฉํฉ๋๋ค.
- ๊ฒฝ๋ก ํ์: ๊ทธ๋ํ๋ ํธ๋ฆฌ์์ ๊ฒฝ๋ก๋ฅผ ํ์ํ ๋ ์ ์ฉํ๋ฉฐ, ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ํ์ํ๋ ๋ฌธ์ ์ ์ ํฉํฉ๋๋ค.
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๋ ์์ ๋ ธ๋์์ ์ถ๋ฐํ์ฌ ๊น์ด ์๋ ๋ ธ๋๋ฅผ ๋จผ์ ํ์ํฉ๋๋ค.
- ์ฌ๊ท์ ๋๋ ๋ฐ๋ณต์ ์ ๊ทผ: ์ฌ๊ท์ ์ผ๋ก ํจ์ ํธ์ถ์ ํตํด ๊น์ด ์๋ ๋ ธ๋๋ฅผ ํ์ํ๊ฑฐ๋, ์คํ์ ์ฌ์ฉํ์ฌ ๋ฐ๋ณต์ ์ผ๋ก ๋ ธ๋๋ฅผ ํ์ํฉ๋๋ค.
- ๋ฐฉ๋ฌธ ํ์: ๊ฐ ๋ ธ๋๋ ๋ฐฉ๋ฌธ๋๋ฉด ๋ฐฉ๋ฌธ ํ์๋ฅผ ํฉ๋๋ค.
- ๋ฐฑํธ๋ํน: ๋ ์ด์ ๊น์ด ๊ฐ ์ ์๋ ๊ฒฝ์ฐ, ์ด์ ๋ ธ๋๋ก ๋๋์๊ฐ์ ๋ค๋ฅธ ๊ฒฝ๋ก๋ฅผ ํ์ํฉ๋๋ค.
DFS์ ์๊ฐ ๋ณต์ก๋๋ ๊ทธ๋ํ์ ๋ ธ๋ ์(V)์ ์ฃ์ง ์(E)์ ๋ฐ๋ผ O(V + E)์ ๋๋ค. ์ด๋ ๋ชจ๋ ๋ ธ๋์ ์ฃ์ง๋ฅผ ํ ๋ฒ์ฉ ๋ฐฉ๋ฌธํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํธ๋ฆฌ์ ๊ฒฝ์ฐ ๋ ธ๋ ์๊ฐ n์ผ ๋, ์๊ฐ ๋ณต์ก๋๋ O(n)์ ๋๋ค.
DFS๋ ๊ฒฝ๋ก ํ์, ์ฌ์ดํด ํ์ง, ๊ฐ๋ ฅ ์ฐ๊ฒฐ ์์ ์ฐพ๊ธฐ ๋ฑ ๋ค์ํ ๋ฌธ์ ์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค. ๋ํ, ๊ทธ๋ํ์ ๋ชจ๋ ๋ ธ๋๋ฅผ ๋ฐฉ๋ฌธํด์ผ ํ๋ ๋ฌธ์ ์ ์ ํฉํฉ๋๋ค.
์ด์ง ํ(Binary Heap)์ ์์ ์ด์ง ํธ๋ฆฌ(Complete Binary Tree)์ ์ผ์ข ์ผ๋ก, ํ ์์ฑ์ ๋ง์กฑํ๋ ์๋ฃ ๊ตฌ์กฐ์ ๋๋ค. ํ ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ํํ๋ก ๊ตฌ๋ถ๋ฉ๋๋ค:
- ์ต๋ ํ(Max Heap): ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ์ด ์์ ๋ ธ๋์ ๊ฐ๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ์ ๊ตฌ์กฐ.
- ์ต์ ํ(Min Heap): ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ์ด ์์ ๋ ธ๋์ ๊ฐ๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์ ๊ตฌ์กฐ.
- ์์ ์ด์ง ํธ๋ฆฌ: ์ด์ง ํ์ ํญ์ ์์ ์ด์ง ํธ๋ฆฌ์ ๋๋ค. ์ฆ, ๋ชจ๋ ๋ ๋ฒจ์ด ์์ ํ ์ฑ์์ ธ ์๊ณ , ๋ง์ง๋ง ๋ ๋ฒจ์ ๊ฒฝ์ฐ ์ผ์ชฝ๋ถํฐ ์ฐจ๋ก๋๋ก ๋ ธ๋๊ฐ ์ฑ์์ ธ ์์ต๋๋ค.
- ํ ์์ฑ: ์ต๋ ํ์์๋ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ์ด ์์ ๋ ธ๋์ ๊ฐ๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ๊ณ , ์ต์ ํ์์๋ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ์ด ์์ ๋ ธ๋์ ๊ฐ๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์ต๋๋ค.
์ด์ง ํ์ ์ฃผ๋ก ๋ฐฐ์ด์ ์ฌ์ฉํ์ฌ ๊ตฌํ๋ฉ๋๋ค. ๋ฐฐ์ด์ ์ฌ์ฉํ๋ฉด ๋ถ๋ชจ์ ์์ ๋ ธ๋ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ธ๋ฑ์ค๋ฅผ ํตํด ์ฝ๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.
- ๋ถ๋ชจ ๋ ธ๋์ ์ธ๋ฑ์ค: 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)๋ ๊ฐ ์์๊ฐ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก, ์ผ๋ฐ์ ์ธ ํ์ ๋ฌ๋ฆฌ ์์๋ค์ด ์ฐ์ ์์์ ๋ฐ๋ผ ์ ๊ฑฐ๋ฉ๋๋ค. ์ฐ์ ์์ ํ๋ ํ์ ์ผ์ข ์ด์ง๋ง, ์์๋ฅผ ์ฝ์ ํ ๋ ๊ทธ ์ฐ์ ์์์ ๋ฐ๋ผ ์ ์ ํ ์์น์ ๋ฐฐ์นํ๊ณ , ์ ๊ฑฐํ ๋๋ ๊ฐ์ฅ ๋์(๋๋ ๋ฎ์) ์ฐ์ ์์๋ฅผ ๊ฐ์ง ์์๋ฅผ ๋จผ์ ์ ๊ฑฐํฉ๋๋ค.
- ์ฐ์ ์์์ ๋ฐ๋ฅธ ์์ ๊ด๋ฆฌ: ๊ฐ ์์๋ ์ฐ์ ์์๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ํ์ ์์๋ ์ฐ์ ์์์ ๋ฐ๋ผ ์ ๋ ฌ๋ฉ๋๋ค.
- ์ฝ์ ๋ฐ ์ ๊ฑฐ: ์ฝ์ ์ฐ์ฐ๊ณผ ์ ๊ฑฐ ์ฐ์ฐ์ ๋ชจ๋ ์ฐ์ ์์๋ฅผ ๊ณ ๋ คํ์ฌ ์ํ๋ฉ๋๋ค.
- ์์ฉ ๋ถ์ผ: ์์ ์ค์ผ์ค๋ง, ๋คํธ์ํฌ ํธ๋ํฝ ๊ด๋ฆฌ, ์๋ฎฌ๋ ์ด์ ์์คํ ๋ฑ์์ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
์ฐ์ ์์ ํ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ ์ ์์ง๋ง, ๊ฐ์ฅ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ํ(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());
- ์์ ์ค์ผ์ค๋ง: ์ฐ์ ์์๊ฐ ๋์ ์์ ์ ๋จผ์ ์ฒ๋ฆฌํด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
- ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ: ๊ทธ๋ํ์์ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ด๋ฒคํธ ๊ด๋ฆฌ ์์คํ : ์ด๋ฒคํธ๋ฅผ ์ฐ์ ์์์ ๋ฐ๋ผ ์ฒ๋ฆฌํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
- ๋คํธ์ํฌ ํธ๋ํฝ ๊ด๋ฆฌ: ๋ฐ์ดํฐ ํจํท์ ์ฐ์ ์์๋ฅผ ์ ํด ์ ์ก ์์๋ฅผ ๊ฒฐ์ ํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
์ฐ์ ์์ ํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ฌธ์ ๋ฅผ ํจ์จ์ ์ผ๋ก ํด๊ฒฐํ๋ ๋ฐ ์ ์ฉํ ์๋ฃ ๊ตฌ์กฐ์ ๋๋ค. ํนํ, ํ์ ์ฌ์ฉํ์ฌ ๊ตฌํํ๋ฉด ์ฝ์ ๊ณผ ์ญ์ ์ฐ์ฐ์ ํจ์จ์ ์ผ๋ก ์ํํ ์ ์์ด ๋ค์ํ ์์ฉ ๋ถ์ผ์์ ํ์ฉ๋ฉ๋๋ค.
ํด์ ํ ์ด๋ธ(Hash Table)์ ํค(Key)์ ๊ฐ(Value)์ ์์ ์ ์ฅํ๊ณ , ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์, ์ฝ์ , ์ญ์ ํ ์ ์๋ ์๋ฃ ๊ตฌ์กฐ์ ๋๋ค. ํด์ ํ ์ด๋ธ์ ํด์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํค๋ฅผ ํด์ ๊ฐ์ผ๋ก ๋ณํํ๊ณ , ์ด๋ฅผ ์ธ๋ฑ์ค๋ก ์ฌ์ฉํด ๋ฐฐ์ด์ ๊ฐ์ ์ ์ฅํฉ๋๋ค.
- ๋น ๋ฅธ ๊ฒ์, ์ฝ์ , ์ญ์ : ํ๊ท ์ ์ผ๋ก O(1)์ ์๊ฐ ๋ณต์ก๋๋ก ๊ฒ์, ์ฝ์ , ์ญ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
- ํด์ ํจ์(Hash Function): ํค๋ฅผ ์ ๋ ฅ๋ฐ์ ๊ณ ์ ๋ ํฌ๊ธฐ์ ํด์ ๊ฐ(์ฃผ๋ก ์ ์)์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ์ข์ ํด์ ํจ์๋ ํค๋ฅผ ๊ณ ๋ฅด๊ฒ ๋ถํฌ์ํค๊ณ ์ถฉ๋์ ์ต์ํํฉ๋๋ค.
- ์ถฉ๋(Collision): ์๋ก ๋ค๋ฅธ ํค๊ฐ ๋์ผํ ํด์ ๊ฐ์ ๊ฐ๋ ์ํฉ์ ์ถฉ๋์ด๋ผ๊ณ ํฉ๋๋ค. ์ถฉ๋์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ฒด์ด๋(Chaining)๊ณผ ๊ฐ๋ฐฉ ์ฃผ์๋ฒ(Open Addressing)์ด ์์ต๋๋ค.
- ์ฒด์ด๋(Chaining): ๊ฐ ๋ฐฐ์ด ์์๋ฅผ ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ก ๊ด๋ฆฌํ์ฌ, ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ํด๋น ์ธ๋ฑ์ค์ ๋ฆฌ์คํธ์ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ์์ ๋๋ค.
- ๊ฐ๋ฐฉ ์ฃผ์๋ฒ(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"]
- ๋น ๋ฅธ ๋ฐ์ดํฐ ์ ๊ทผ: ํ๊ท ์ ์ผ๋ก O(1) ์๊ฐ ๋ณต์ก๋๋ก ๋ฐ์ดํฐ ์ ๊ทผ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๊ฐ๋จํ ๊ตฌํ: ๋น๊ต์ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์์ผ๋ฉฐ, ๋๋ถ๋ถ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ๋ด์ฅ ์๋ฃ ๊ตฌ์กฐ๋ก ์ ๊ณต๋ฉ๋๋ค.
- ์ถฉ๋ ์ฒ๋ฆฌ: ์ถฉ๋์ด ๋ฐ์ํ๋ฉด ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ถ๊ฐ์ ์ธ ๊ตฌ์กฐ๊ฐ ํ์ํฉ๋๋ค.
- ๊ณต๊ฐ ๋ญ๋น: ํด์ ํ ์ด๋ธ์ ํฌ๊ธฐ๋ฅผ ์ ์ ํ๊ฒ ์ค์ ํ์ง ์์ผ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์ ๋ ฌ๋์ง ์์ ๋ฐ์ดํฐ: ๋ฐ์ดํฐ๊ฐ ํน์ ์์๋ก ์ ์ฅ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ ๋ ฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ์ ํฉํ์ง ์์ต๋๋ค.
- ์บ์ฑ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ ๊ฒฐ๊ณผ ๋ฑ์ ์บ์ฑํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
- ์งํฉ ์ฐ์ฐ: ์งํฉ์ ํฌํจ ์ฌ๋ถ๋ฅผ ๋น ๋ฅด๊ฒ ํ์ธํ ์ ์๋ ์๋ฃ ๊ตฌ์กฐ๋ก ์ฌ์ฉ๋ฉ๋๋ค.
- ์ฐ๊ด ๋ฐฐ์ด: ํค์ ๊ฐ์ ๋งตํํ๋ ์ฐ๊ด ๋ฐฐ์ด์ด๋ ์ฌ์ ์ ๊ตฌํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
ํด์ ํ ์ด๋ธ์ ๋งค์ฐ ๊ฐ๋ ฅํ๊ณ ํจ์จ์ ์ธ ์๋ฃ ๊ตฌ์กฐ๋ก, ๋ง์ ์๊ณ ๋ฆฌ์ฆ๊ณผ ์์คํ ์์ ํ์์ ์ธ ์ญํ ์ ํฉ๋๋ค.
๊ทธ๋ํ(Graph)๋ ์ ์ (Vertex)๊ณผ ๊ฐ์ (Edge)์ผ๋ก ์ด๋ฃจ์ด์ง ์๋ฃ ๊ตฌ์กฐ๋ก, ์ ์ ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ํ๋ ๋ค์ํ ํํ๋ก ์กด์ฌํ๋ฉฐ, ์ฌ๋ฌ ๊ฐ์ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
- ์ ์ (Vertex): ๊ทธ๋ํ์ ๋ ธ๋๋ฅผ ์๋ฏธํฉ๋๋ค. ์ ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค.
- ๊ฐ์ (Edge): ์ ์ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ๋ ๋๋ค. ๊ฐ์ ์ ๋ฐฉํฅ์ด ์์ ์๋(์ ํฅ ๊ทธ๋ํ) ์์ ์๋(๋ฌดํฅ ๊ทธ๋ํ) ์์ต๋๋ค.
- ์ธ์ ์ ์ (Adjacent Vertex): ๊ฐ์ ์ผ๋ก ์ง์ ์ฐ๊ฒฐ๋ ์ ์ ๋ค์ ๋๋ค.
- ๊ฒฝ๋ก(Path): ํ ์ ์ ์์ ์์ํ์ฌ ๋ค๋ฅธ ์ ์ ์ผ๋ก ๊ฐ๋ ์ผ๋ จ์ ๊ฐ์ ๋ค์ ๋๋ค.
- ๊ฐ์ค์น(Weight): ๊ฐ์ ์ ๋ถ์ฌ๋ ๊ฐ์ผ๋ก, ๋ ์ ์ ๊ฐ์ ๋น์ฉ์ด๋ ๊ฑฐ๋ฆฌ๋ฅผ ๋ํ๋ ๋๋ค. ๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ๋ฅผ ๊ฐ์ค์น ๊ทธ๋ํ(Weighted Graph)๋ผ๊ณ ํฉ๋๋ค.
- ๋ฌดํฅ ๊ทธ๋ํ(Undirected Graph): ๊ฐ์ ์ ๋ฐฉํฅ์ด ์๋ ๊ทธ๋ํ์ ๋๋ค.
- ์ ํฅ ๊ทธ๋ํ(Directed Graph): ๊ฐ์ ์ ๋ฐฉํฅ์ด ์๋ ๊ทธ๋ํ์ ๋๋ค.
- ๊ฐ์ค์น ๊ทธ๋ํ(Weighted Graph): ๊ฐ์ ์ ๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ์ ๋๋ค.
- ๋น๊ฐ์ค์น ๊ทธ๋ํ(Unweighted Graph): ๊ฐ์ ์ ๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ์ ๋๋ค.
- ์ธ์ ํ๋ ฌ(Adjacency Matrix): ์ ์ ์ ํ๊ณผ ์ด๋ก ํํํ๊ณ , ์ ์ ๊ฐ์ ์ฐ๊ฒฐ์ ํ๋ ฌ์ ๊ฐ์ผ๋ก ๋ํ๋ ๋๋ค. ์ฐ๊ฒฐ๋์ด ์์ผ๋ฉด 1, ์ฐ๊ฒฐ๋์ด ์์ง ์์ผ๋ฉด 0์ผ๋ก ํ์ํฉ๋๋ค. ๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ์์๋ ๊ฐ์ค์น๋ฅผ ํ๋ ฌ์ ๊ฐ์ผ๋ก ํ์ํฉ๋๋ค.
- ์ธ์ ๋ฆฌ์คํธ(Adjacency List): ๊ฐ ์ ์ ์ ๋ํด ์ธ์ ํ ์ ์ ๋ค์ ๋ฆฌ์คํธ๋ฅผ ์ ์ฅํฉ๋๋ค. ์ธ์ ๋ฆฌ์คํธ๋ ๊ณต๊ฐ ํจ์จ์ฑ์ด ์ข๊ณ , ๊ทธ๋ํ์ ์ ์ ๊ณผ ๊ฐ์ ์ด ๋ง์ ๋ ์ ๋ฆฌํฉ๋๋ค.
์ธ์ ํ๋ ฌ์ ์ ์ ์ ํ๊ณผ ์ด๋ก ํ์ํ๊ณ , ๋ ์ ์ ์ฌ์ด์ ๊ฐ์ ์ด ์กด์ฌํ๋ฉด ํด๋น ํ๋ ฌ ์์น์ 1(๋๋ ๊ฐ์ค์น ๊ฐ)์, ์กด์ฌํ์ง ์์ผ๋ฉด 0์ ๊ธฐ๋กํฉ๋๋ค.
- ๊ณต๊ฐ ๋ณต์ก๋: (O(V^2)) - (V)๋ ์ ์ ์ ์
- ๊ฐ์ ์ถ๊ฐ: (O(1))
- ๊ฐ์ ์ญ์ : (O(1))
- ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ: (O(1))
- ์ ์ ์ ๋ชจ๋ ์ธ์ ์ ์ ํ์: (O(V))
- ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ์ด ๋น ๋ฆ: ํน์ ๋ ์ ์ ์ฌ์ด์ ๊ฐ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ (O(1)) ์๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
- ๊ฐ์ ์ถ๊ฐ/์ญ์ ๊ฐ ๋น ๋ฆ: (O(1)) ์๊ฐ์ ๊ฐ์ ์ ์ถ๊ฐํ๊ฑฐ๋ ์ญ์ ํ ์ ์์ต๋๋ค.
- ๊ณต๊ฐ ๋นํจ์จ์ฑ: ์ ์ ์ ์๊ฐ ๋ง๊ณ ๊ฐ์ ์ ์๊ฐ ์ ์ ๊ฒฝ์ฐ(ํฌ์ ๊ทธ๋ํ) ๋ง์ ๊ณต๊ฐ์ด ๋ญ๋น๋ฉ๋๋ค.
- ์ ์ ์ ์ธ์ ์ ์ ํ์์ด ๋๋ฆผ: ํน์ ์ ์ ์ ๋ชจ๋ ์ธ์ ์ ์ ์ ์ฐพ์ผ๋ ค๋ฉด ํ๋ ฌ์ ํด๋น ํ ์ ์ฒด๋ฅผ ํ์ธํด์ผ ํ๋ฏ๋ก \(O(V)\) ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
์ธ์ ๋ฆฌ์คํธ๋ ๊ฐ ์ ์ ์ ๋ํด ์ฐ๊ฒฐ๋ ์ธ์ ์ ์ ์ ๋ฆฌ์คํธ๋ฅผ ์ ์ฅํฉ๋๋ค. ๋ฐฐ์ด์ด๋ ๋งํฌ๋ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํด ๊ตฌํํ ์ ์์ต๋๋ค.
- ๊ณต๊ฐ ๋ณต์ก๋: (O(V + E)) - (E)๋ ๊ฐ์ ์ ์
- ๊ฐ์ ์ถ๊ฐ: (O(1))
- ๊ฐ์ ์ญ์ : (O(E / V)) ํ๊ท ์ ์ผ๋ก, ์ต์ ์ ๊ฒฝ์ฐ (O(V))
- ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ: (O(E / V)) ํ๊ท ์ ์ผ๋ก, ์ต์ ์ ๊ฒฝ์ฐ (O(V))
- ์ ์ ์ ๋ชจ๋ ์ธ์ ์ ์ ํ์: (O(V)) ์ต์ ์ ๊ฒฝ์ฐ, ํ์ง๋ง ํ๊ท ์ ์ผ๋ก ์ธ์ ํ ์ ์ ์ ์์ ๋น๋ก
- ๊ณต๊ฐ ํจ์จ์ฑ: ํฌ์ ๊ทธ๋ํ์ ๊ฒฝ์ฐ ๊ณต๊ฐ์ ์ ์ฝํ ์ ์์ต๋๋ค.
- ์ ์ ์ ์ธ์ ์ ์ ํ์์ด ๋น ๋ฆ: ํน์ ์ ์ ์ ๋ชจ๋ ์ธ์ ์ ์ ์ ๋น ๋ฅด๊ฒ ํ์ํ ์ ์์ต๋๋ค. ํ๊ท ์ ์ผ๋ก ์ธ์ ํ ์ ์ ์ ์์ ๋น๋กํ ์๊ฐ์ ํ์์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ์ด ๋๋ฆผ: ํน์ ๋ ์ ์ ์ฌ์ด์ ๊ฐ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ํ์ธํ๋ ค๋ฉด ์ธ์ ๋ฆฌ์คํธ๋ฅผ ์ํํด์ผ ํ๋ฏ๋ก ์ต์ ์ ๊ฒฝ์ฐ (O(V)) ์๊ฐ์ด ๊ฑธ๋ฆฝ๋๋ค.
- ๊ฐ์ ์ญ์ ๊ฐ ๋๋ฆผ: ๊ฐ์ ์ ์ญ์ ํ๋ ค๋ฉด ์ธ์ ๋ฆฌ์คํธ์์ ํด๋น ๊ฐ์ ์ ์ฐพ์์ผ ํ๋ฏ๋ก ์๊ฐ์ด ๋ ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
- ๊ทธ๋ํ์ ๋ฐ๋: ๊ทธ๋ํ๊ฐ ๋ฐ์ง๋์ด ์๊ณ ๊ฐ์ ์ ์๊ฐ ์ ์ ์ ์์ ์ ๊ณฑ์ ๋น๋กํ๋ค๋ฉด ์ธ์ ํ๋ ฌ์ด ์ ํฉํฉ๋๋ค. ๋ฐ๋๋ก, ํฌ์ ๊ทธ๋ํ์์๋ ์ธ์ ๋ฆฌ์คํธ๊ฐ ๊ณต๊ฐ ํจ์จ์ฑ์ด ๋์ต๋๋ค.
- ๊ฐ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ: ๋ ์ ์ ์ฌ์ด์ ๊ฐ์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๋น๋ฒํ๊ฒ ํ์ธํด์ผ ํ๋ค๋ฉด ์ธ์ ํ๋ ฌ์ด ๋ ํจ์จ์ ์ ๋๋ค.
- ์ ์ ์ ์ธ์ ์ ์ ํ์: ํน์ ์ ์ ์ ๋ชจ๋ ์ธ์ ์ ์ ์ ์์ฃผ ํ์ํด์ผ ํ๋ค๋ฉด ์ธ์ ๋ฆฌ์คํธ๊ฐ ๋ ํจ์จ์ ์ ๋๋ค.
์ด๋ฌํ ๋น๊ต์ ์ฅ๋จ์ ์ ๊ณ ๋ คํ์ฌ, ๊ทธ๋ํ์ ํน์ฑ๊ณผ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ์ ํฉํ ํํ ๋ฐฉ๋ฒ์ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
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);
- ๋๋น ์ฐ์ ํ์(BFS, Breadth-First Search): ์์ ์ ์ ์์ ๊ฐ๊น์ด ์ ์ ๋ถํฐ ํ์ํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ฃผ๋ก ํ(Queue)๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํฉ๋๋ค.
- ๊น์ด ์ฐ์ ํ์(DFS, Depth-First Search): ์์ ์ ์ ์์ ํ ๋ฐฉํฅ์ผ๋ก ๊น์ด ํ์ํ๋ค๊ฐ ๋ ์ด์ ๊ฐ ์ ์์ผ๋ฉด ๋ค๋ฅธ ๊ฒฝ๋ก๋ก ํ์ํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ฃผ๋ก ์คํ(Stack)์ ์ฌ์ฉํ์ฌ ๊ตฌํํ๊ฑฐ๋ ์ฌ๊ท ํธ์ถ๋ก ๊ตฌํํฉ๋๋ค.
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;
}
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' ]
*/
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' ]
*/
- ๋คํธ์ํฌ: ์ปดํจํฐ ๋คํธ์ํฌ, ์์ ๋คํธ์ํฌ ๋ฑ์์ ๋ ธ๋ ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ๋ด๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
- ๊ฒฝ๋ก ์ฐพ๊ธฐ: ์ง๋๋ ๊ธธ ์ฐพ๊ธฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
- ์ผ์ ๊ด๋ฆฌ: ํ๋ก์ ํธ ๊ด๋ฆฌ์์ ์์ ๊ฐ์ ์์กด์ฑ์ ๋ํ๋ด๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
- ์์ ๊ณ์ฐ: ํ์ด์ง ๋ญํฌ ์๊ณ ๋ฆฌ์ฆ๊ณผ ๊ฐ์ ๊ฒ์ ์์ง์์ ํ์ด์ง์ ์ค์๋๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
๊ทธ๋ํ๋ ๋ฐ์ดํฐ ๊ฐ์ ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ ๋ฐ ๋งค์ฐ ์ ์ฉํ ์๋ฃ ๊ตฌ์กฐ๋ก, ๋ค์ํ ๋ถ์ผ์์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ(Dijkstra's Algorithm)์ ๊ทธ๋ํ์์ ํ ์ ์ ์์ ๋ค๋ฅธ ๋ชจ๋ ์ ์ ์ผ๋ก์ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ๋ ๋ฐ ์ฌ์ฉ๋๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ์ค์น๊ฐ ์๋ ๊ทธ๋ํ์์ ์ฌ์ฉ๋๋ฉฐ, ๊ฐ์ค์น๊ฐ ์์๊ฐ ์๋ ๊ฒฝ์ฐ์๋ง ์ ์ฉํ ์ ์์ต๋๋ค.
- ์์ ์ ์ ์ ํ: ์๊ณ ๋ฆฌ์ฆ์ ์์ ์ ์ ์์ ์์ํฉ๋๋ค.
- ์ต๋จ ๊ฒฝ๋ก ์งํฉ: ์ต๋จ ๊ฒฝ๋ก๋ฅผ ํ์ ํ ์ ์ ๋ค์ ์งํฉ์ ์ ์งํฉ๋๋ค.
- ๋ฏธํ์ ์งํฉ: ์์ง ์ต๋จ ๊ฒฝ๋ก๊ฐ ํ์ ๋์ง ์์ ์ ์ ๋ค์ ์งํฉ์ ์ ์งํฉ๋๋ค.
- ๊ฑฐ๋ฆฌ ๋ฐฐ์ด: ์์ ์ ์ ์์ ๊ฐ ์ ์ ๊น์ง์ ํ์ฌ๊น์ง ๋ฐ๊ฒฌ๋ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ์ ์ฅํฉ๋๋ค. ์ด๊ธฐ์๋ ์์ ์ ์ ์ ๊ฑฐ๋ฆฌ๋ฅผ 0์ผ๋ก ์ค์ ํ๊ณ ๋๋จธ์ง ์ ์ ์ ๊ฑฐ๋ฆฌ๋ฅผ ๋ฌดํ๋๋ก ์ค์ ํฉ๋๋ค.
- ์ด์ ์ ์ ์ ๋ฐ์ดํธ: ํ์ฌ ์ ์ ์์ ์ธ์ ํ ์ ์ ๋ค๋ก์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํ๊ณ , ๋ ์งง์ ๊ฒฝ๋ก๋ฅผ ๋ฐ๊ฒฌํ๋ฉด ๊ฑฐ๋ฆฌ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ๋ฐ๋ณต: ๋ชจ๋ ์ ์ ์ ์ต๋จ ๊ฒฝ๋ก๊ฐ ํ์ ๋ ๋๊น์ง ์ด ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค.
- ์์ ์ ์ ์ ์ค์ ํ๊ณ , ์์ ์ ์ ์ ๊ฑฐ๋ฆฌ๋ฅผ 0์ผ๋ก ์ค์ ํฉ๋๋ค.
- ํ์ฌ ์ ์ ์์ ์ธ์ ํ ๋ชจ๋ ์ ์ ์ ๊ฑฐ๋ฆฌ๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ์์ง ๋ฐฉ๋ฌธํ์ง ์์ ์ ์ ์ค ๊ฐ์ฅ ๊ฑฐ๋ฆฌ๊ฐ ์งง์ ์ ์ ์ ์ ํํ์ฌ, ๊ทธ ์ ์ ์ผ๋ก ์ด๋ํฉ๋๋ค.
- ์ด ๊ณผ์ ์ ๋ชจ๋ ์ ์ ์ด ๋ฐฉ๋ฌธ๋ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค.
- ์ด ํจ์๋ ์์ ์ ์ ๊ณผ ๋ ์ ์ ์ ๋ฐ์์ผ ํฉ๋๋ค.
- ๊ฐ์ฒด(์ด๋ฅผ 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))
- ๋จ์ผ ์์์ : ์์ ์ ์ ์์ ๋ค๋ฅธ ๋ชจ๋ ์ ์ ์ผ๋ก์ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ๊ตฌํฉ๋๋ค.
- ๋น์์ ๊ฐ์ค์น: ๊ฐ์ ์ ๊ฐ์ค์น๊ฐ ์์์ธ ๊ฒฝ์ฐ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํจ์จ์ฑ: ์ฐ์ ์์ ํ(ํ)๋ฅผ ์ฌ์ฉํ๋ฉด ํฐ ๊ทธ๋ํ์์๋ ๋น๊ต์ ํจ์จ์ ์ผ๋ก ์๋ํฉ๋๋ค.
๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ์ ๋คํธ์ํฌ ๋ผ์ฐํ , ์ง๋ ์๋น์ค, ๊ตํต ์์คํ ๋ฑ ๋ค์ํ ๋ถ์ผ์์ ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค.
๋์ ํ๋ก๊ทธ๋๋ฐ(Dynamic Programming, DP)์ ๋ณต์กํ ๋ฌธ์ ๋ฅผ ๋ ์์ ํ์ ๋ฌธ์ ๋ก ๋๋์ด ํด๊ฒฐํ๋ ์๊ณ ๋ฆฌ์ฆ ์ค๊ณ ๊ธฐ๋ฒ์ ๋๋ค. ์ด ๊ธฐ๋ฒ์ ํ์ ๋ฌธ์ ์ ํด๋ฅผ ์ฌ์ฌ์ฉํ์ฌ ์ ์ฒด ๋ฌธ์ ์ ํด๋ฅผ ๊ตฌํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋์ ํ๋ก๊ทธ๋๋ฐ์ ์ฃผ๋ก ์ต์ ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ, ๋ ๊ฐ์ง ์ค์ํ ์์ฑ์ ๊ฐ์ง๋๋ค: **์ต์ ๋ถ๋ถ ๊ตฌ์กฐ(Optimal Substructure)**์ ์ค๋ณต ๋ถ๋ถ ๋ฌธ์ (Overlapping Subproblems).
- ์ต์ ๋ถ๋ถ ๊ตฌ์กฐ(Optimal Substructure):
- ํฐ ๋ฌธ์ ์ ์ต์ ํด๊ฐ ๊ทธ ๋ถ๋ถ ๋ฌธ์ ์ ์ต์ ํด๋ก๋ถํฐ ์ ๋๋ ์ ์๋ ์์ฑ์ ์๋ฏธํฉ๋๋ค.
- ์๋ฅผ ๋ค์ด, ์ต๋จ ๊ฒฝ๋ก ๋ฌธ์ ์์ ์ ์ฒด ๊ฒฝ๋ก์ ์ต์ ํด๋ ๊ทธ ๊ฒฝ๋ก๋ฅผ ๊ตฌ์ฑํ๋ ๋ถ๋ถ ๊ฒฝ๋ก๋ค์ ์ต์ ํด๋ก ๊ตฌ์ฑ๋ ์ ์์ต๋๋ค.
- ์ค๋ณต ๋ถ๋ถ ๋ฌธ์ (Overlapping Subproblems):
- ๋์ผํ ๋ถ๋ถ ๋ฌธ์ ๊ฐ ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณตํ์ฌ ๊ณ์ฐ๋๋ ์์ฑ์ ์๋ฏธํฉ๋๋ค.
- ๋์ ํ๋ก๊ทธ๋๋ฐ์ ์ด๋ฌํ ์ค๋ณต ๊ณ์ฐ์ ํผํ๊ธฐ ์ํด ์ด๋ฏธ ๊ณ์ฐ๋ ๊ฐ์ ์ ์ฅํ๊ณ ์ฌ์ฌ์ฉํฉ๋๋ค.
- ํ๋ค์ด(๋ฉ๋ชจ์ด์ ์ด์
, Memoization):
- ์ฌ๊ท์ ์ ๊ทผ ๋ฐฉ์์ผ๋ก, ๋ฌธ์ ๋ฅผ ์ฌ๊ท์ ์ผ๋ก ๋๋๊ณ , ๊ฐ ํ์ ๋ฌธ์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ์ฌ ํ์ํ ๋ ๋ค์ ์ฌ์ฉํฉ๋๋ค.
- ํ์ํ ๋ ๊ณ์ฐํ๋ฏ๋ก, ์ฒ์์๋ ๊ณ์ฐํ์ง ์๊ณ ์์ฒญ ์ ๊ณ์ฐํ์ฌ ์บ์์ ์ ์ฅํฉ๋๋ค.
- ๋ฐํ
์
(ํ
์ด๋ธ๋ง, 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
]
*/
- ์๊ฐ ๋ณต์ก๋ ๊ฐ์ : ์ค๋ณต ๊ณ์ฐ์ ํผํ๊ณ , ๊ฐ ํ์ ๋ฌธ์ ๋ฅผ ํ ๋ฒ๋ง ๊ณ์ฐํ๋ฏ๋ก ์๊ฐ ๋ณต์ก๋๊ฐ ํฌ๊ฒ ๊ฐ์ ๋ฉ๋๋ค.
- ๊ณต๊ฐ ๋ณต์ก๋: ๋ฉ๋ชจ์ด์ ์ด์ ์ด๋ ํ ์ด๋ธ์ ์ ์ฅํ๋ ๋ฐ ํ์ํ ์ถ๊ฐ ๊ณต๊ฐ์ด ํ์ํ์ง๋ง, ์๊ฐ ๋ณต์ก๋ ๊ฐ์ ์ ๋นํด ํฐ ์ด์ ์ด ์์ต๋๋ค.
- ์ ์ฉ ๋ฒ์: ์ต์ ํ ๋ฌธ์ , ๊ฒฝ๋ก ์ฐพ๊ธฐ ๋ฌธ์ , ๋ถ๋ถ ์งํฉ ๋ฌธ์ ๋ฑ ๋ค์ํ ๋ฌธ์ ์ ์ ์ฉํ ์ ์์ต๋๋ค.