- 순차 탐색 vs. 이진 탐색
- 예) 값이 12인 원소의 위치를 찾기
> 순차 탐색: 리스트 안에 있는 특정한 데이터를 찾기 위해 앞에서부터 하나씩 확인
==> 탐색을 위한 시간 복잡도: O(N)
> 이진 탐색: 정렬되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색
==> 탐색을 위한 시간 복잡도: O(logN)
- 예) 값이 12인 원소의 위치를 찾기
- 이진 탐색(Binary Search) 동작 방식
- 시작점(left) 와 끝점(end)을 기준으로 탐색 범위를 명시
- 이진 탐색의 시간 복잡도
- 각 단계마다 탐색 범위를 2로 나누는 것으로 이해할 수 있다.
- 이상적인 경우 매 단계마다 범위가 반으로 감소하므로, 로그(log) 복잡도를 가진다.
- 대표적인 예시
- 매우 넓은(억 단위 이상) 탐색 범위에서 최적의 해를 찾아야 하는 경우
- 데이터를 정렬한 뒤에 다수의 쿼리(query)를 날려야 하는 경우
- 이진 탐색 코드(재귀 함수)
// 이진 탐색(재귀 함수)
function binarySearch(arr, target, start, end) {
if (start > end) return -1;
let mid = parseInt((start + end) / 2);
// 찾은 경우 중간점 인덱스 반환
if (arr[mid] == target) return mid;
// 중간점의 값보다 찾고자 하는 값이 작은 경우 왼쪽 확인
else if (arr[mid] > target) return binarySearch(arr, target, start, mid - 1);
// 중간점의 값보다 찾고자 하는 값이 큰 경우 오른쪽 확인
else return binarySearch(arr, target, mid + 1, end);
}
// n(원소의 개수)와 target(찾고자 하는 값)
let n = 10;
let target = 7;
arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
// 이진 탐색 수행 결과 출력
let result = binarySearch(arr, target, 0, n - 1);
if (result == -1) console.log('원소가 존재하지 않습니다.');
else console.log(`${result + 1}번째 원소입니다.`);
- 이진 탐색 코드(반복문)
// 이진 탐색(재귀 함수)
function binarySearch(arr, target, start, end) {
while (start <= end) {
let mid = parseInt((start + end) / 2);
// 찾은 경우 중간점 인덱스 반환
if (arr[mid] == target) return mid;
// 중간점의 값보다 찾고자 하는 값이 작은 경우 왼쪽 확인
else if (arr[mid] > target) end = mid - 1;
// 중간점의 값보다 찾고자 하는 값이 큰 경우 오른쪽 확인
else start = mid + 1;
}
return -1;
}
// n(원소의 개수)와 target(찾고자 하는 값)
let n = 10;
let target = 7;
arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
// 이진 탐색 수행 결과 출력
let result = binarySearch(arr, target, 0, n - 1);
if (result == -1) console.log('원소가 존재하지 않습니다.');
else console.log(`${result + 1}번째 원소입니다.`);
1. 정렬된 배열에서 특정 원소의 개수 구하기
- 정렬된 배열에서 값이 특정 범위에 해당하는 원소의 개수를 계산
- 하한선과 상한선 함수 활용
- lowerBound(arr, x): 정렬된 순서를 유지하면 배열 arr에 x를 넣을 가장 왼쪽 인덱스를 반환
- upperBound(arr, x): 정렬된 순서를 유지하면서 배열 arr에 x를 넣을 가장 오른쪽 인덱스를 반환
// 정렬된 순서를 유지하면서 배열에 삽입할 가장 왼쪽 인덱스 반환
function lowerBound(arr, target, start, end) {
while (start < end) {
let mid = parseInt((start + end) / 2);
if (arr[mid] >= target) end = mid; // 최대한 왼쪽으로 이동하기
else start = mid + 1;
}
return end;
}
// 정렬된 순서를 유지하면서 배열에 삽입할 가장 오른쪽 인덱스 반환
function upperBound(arr, target, start, end) {
while (start < end) {
let mid = parseInt((start + end) / 2);
if (arr[mid] > target) end = mid;
else start = mid + 1;
}
return end;
}
2. 파라메트릭 서치
- 이진 탐색 조건: 변경할(최적화할) 값 x에 대하여 f(x)가 단조 증가 혹은 단조 감소
- 단조 증가 함수: x ≤ y이면 f(x) ≤ f(y)인 경우
- 일반적으로 조건(constraint)은 f(x)에 대하여 정의된다.
- 파라메트릭 서치(Parametric Search)란?
- 최적화 문제를 결정 문제('예' 혹은 '아니오')로 바꾸어 해결하는 기법
- 이진 탐색을 이용하여 해결할 수 있다.
'JavaScript Dev. > Javascript' 카테고리의 다른 글
JavaScript 동작 원리? (1) | 2024.02.02 |
---|---|
JavaScript 백트래킹 (0) | 2024.01.12 |
JavaScript 탐욕법(Greedy) 알고리즘 (0) | 2023.12.23 |
JavaScript 정렬(sorting) 알고리즘 (0) | 2023.12.15 |
JavaScript 자료구조 (0) | 2023.12.10 |