[Algorithm] 알고리즘의 시간 복잡도와 공간 복잡도
🕰️ 알고리즘에서 복잡도란 무엇인가?
복잡도(Complexity)는 알고리즘의 성능을 측정하는 중요한 지표이다.
알고리즘이 얼마나 효율적으로 문제를 해결하는지 평가하는 기준으로, 주로 시간 복잡도와 공간 복잡도로 나눈다.
- 시간 복잡도: 알고리즘이 실행되는 데 걸리는 시간
- 공간 복잡도: 알고리즘이 수행되는 동안 사용하는 메모리 양
⏱️ 시간 복잡도
시간 복잡도는 알고리즘이 입력 크기에 따라 얼마나 오래 실행되는지를 나타낸다.
🔢 시간 복잡도 표기법
알고리즘의 성능을 수학적으로 표현할 때 주로 Big-O 표기법을 사용한다. Big-O 표기법은 알고리즘의 시간 복잡도를 최악의 경우를 기준으로 나타내며, 알고리즘의 효율성을 쉽게 비교할 수 있게 해준다.
-
O(1) – 상수 시간
입력 크기와 관계없이 일정한 시간이 걸리는 알고리즘을 의미한다.배열의 첫 번째 요소를 접근하는 것과 같은 작업은 O(1)이다.
function constantTime(arr) { return arr[0]; // 항상 첫 번째 요소 반환 }
-
O(n) – 선형 시간
입력 크기 n에 비례하여 시간이 증가하는 알고리즘을 의미한다.배열에서 모든 요소를 순차적으로 검색하는 경우 O(n)이 된다.
function linearSearch(arr, target) { for (let i = 0; i < arr.length; i++) { if (arr[i] === target) return i; } return -1; }
-
O(n^2) – 이차 시간
중첩된 반복문을 사용할 때 자주 나타나는 시간 복잡도이다. 이차 시간 복잡도는 입력 크기 n에 대해 시간이 n의 제곱에 비례하여 증가한다.버블 정렬이나 선택 정렬 같은 정렬 알고리즘에서 O(n^2)가 발생한다.
function bubbleSort(arr) { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length - i - 1; j++) { if (arr[j] > arr[j + 1]) { [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // 두 값 교환 } } } return arr; }
-
O(log n) – 로그 시간
이진 탐색과 같이, 입력 크기를 절반씩 나누면서 문제를 해결하는 알고리즘에서 나타나는 시간 복잡도이다. 이 알고리즘은 효율적으로 작동하며, 입력 크기가 커져도 시간이 그리 많이 증가하지 않는다.정렬된 배열에서 값을 찾기 위해 사용하는 이진 탐색 알고리즘이 O(log n)이다.
function binarySearch(arr, target) { let low = 0, high = arr.length - 1; while (low <= high) { let mid = Math.floor((low + high) / 2); if (arr[mid] === target) return mid; else if (arr[mid] < target) low = mid + 1; else high = mid - 1; } return -1; }
-
O(n log n) – 선형 로그 시간
합병 정렬(Merge Sort)이나 퀵 정렬(Quick Sort)과 같은 정렬 알고리즘은 O(n log n)의 시간 복잡도를 가진다. 이 알고리즘들은 입력 크기에 대해 선형적인 요소와 로그적인 요소가 결합된 형태로 시간이 증가한다.병합 정렬의 알고리즘은 O(n log n)이다.
function mergeSort(arr) { if (arr.length <= 1) return arr; const mid = Math.floor(arr.length / 2); const left = mergeSort(arr.slice(0, mid)); const right = mergeSort(arr.slice(mid)); return merge(left, right); } function merge(left, right) { let result = []; while (left.length && right.length) { result.push(left[0] < right[0] ? left.shift() : right.shift()); } return result.concat(left, right); }
💡 시간 복잡도가 작은 알고리즘일수록 더 효율적이고, O(1) < O(log n) < O(n) < O(n log n) < O(n^2) 순으로 효율성이 떨어진다.
💾 공간 복잡도
공간 복잡도는 알고리즘이 실행되는 동안 사용하는 메모리 양을 나타낸다.
📦 공간 복잡도 표기법
공간 복잡도를 분석할 때도 Big-O 표기법을 사용하여 알고리즘이 사용하는 메모리 양을 나타낸다.
-
O(1) – 상수 공간
입력 크기와 관계없이 일정한 양의 메모리를 사용하는 알고리즘을 의미한다. 이 경우 알고리즘의 공간 복잡도는 입력 크기와 무관하게 일정하다.배열에서 첫 번째 요소를 반환하는 알고리즘은 O(1)의 공간 복잡도를 가진다.
function constantSpace(arr) { let firstElement = arr[0]; // 첫 번째 요소를 저장하는데 고정된 공간만 사용 return firstElement; }
-
O(n) – 선형 공간
입력 크기 n에 비례하여 메모리 사용량이 증가하는 알고리즘을 의미한다.배열을 그대로 복사하는 알고리즘은 O(n)의 공간 복잡도를 가진다.
function copyArray(arr) { let newArr = []; for (let i = 0; i < arr.length; i++) { newArr[i] = arr[i]; // 배열의 크기와 비례하는 공간을 사용 } return newArr; }
-
O(n^2) – 이차 공간
이차 공간 복잡도는 중첩된 데이터 구조나 배열을 사용해야 할 때 나타난다.2D 배열을 생성하는 알고리즘에서는 O(n^2)의 공간 복잡도를 가진다.
function create2DArray(n) { let arr = []; for (let i = 0; i < n; i++) { arr[i] = new Array(n); // 2D 배열을 생성, n^2의 공간 사용 } return arr; }
-
O(log n) – 로그 공간
이 공간 복잡도는 보통 재귀 알고리즘에서 발생한다.이진 탐색에서 사용하는 공간은 O(log n)입니다.
function binarySearchSpace(arr, target, low, high) { if (low > high) return -1; let mid = Math.floor((low + high) / 2); if (arr[mid] === target) return mid; else if (arr[mid] < target) return binarySearchSpace(arr, target, mid + 1, high); else return binarySearchSpace(arr, target, low, mid - 1); }
-
O(2^n) – 지수 공간
지수 공간 복잡도는 주로 재귀적인 문제에서 발생하며, 특히 하위 문제를 중복해서 해결할 때 나타난다.피보나치 수열을 계산하는 재귀적 알고리즘은 O(2^n)의 공간 복잡도를 가진다.
function fibonacci(n) { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); // 지수적인 공간 복잡도 }
💡 공간 복잡도가 작은 알고리즘일수록 더 효율적이고, O(1) < O(log n) < O(n) < O(n^2) < O(2^n) 순서로 효율성이 떨어진다.
🚀 복잡도 분석의 중요성
알고리즘을 설계하고 선택하는 과정에서 시간 복잡도와 공간 복잡도를 이해하는 것은 중요하다. 이를 통해 효율적인 알고리즘을 선택하고 성능을 최적화할 수 있다.
- 효율적인 자원 관리
메모리가 제한된 환경에서는 공간 복잡도가 중요한 성능 지표가 된다. O(1) 또는 O(n) 공간 복잡도를 가진 알고리즘을 선택하는 것이 효율적이다. - 최적화 및 성능 개선
알고리즘의 복잡도를 분석하여 실행 시간을 단축시키고 더 나은 성능을 구현할 수 있다. O(n)에서 O(log n)로 최적화할 수 있는 경우 성능을 크게 향상시킬 수 있다. - 시스템 성능 예측
복잡도 분석을 통해 알고리즘의 성능을 예측하고, 데이터 크기나 시스템 환경에 맞는 최적의 알고리즘을 선택할 수 있다.
알고리즘 선택 시 문제의 특성과 데이터 크기를 고려하여 가장 적합한 알고리즘을 선택하는 것이 중요하다.
Leave a comment