이분 탐색 혹은 이진 탐색
정렬되어 있는 집합에서 원하는 값을 찾는 효과적인 탐색 방법으로 알려진 이분 탐색에 대해 알아본다.
아이디어
큰 틀은 분할 정복 원리를 이용한다.
-> 배열의 가운데 원소 A[mid]와 탐색키 x를 비교한다.
-> 이 때 3가지 케이스로 나뉜다.
(1)탐색키=가운데원소 → 탐색성공(인덱스mid반환후종료)
(2)탐색키<가운데원소 → 순환호출 (이진 탐색(원래 크기 1/2의 왼쪽 부분배열))
(3)탐색키>가운데원소 → 순환호출 (이진 탐색(원래 크기 1/2의 오른쪽 부분배열))
*mid = ( 시작인덱스 i + 마지막 인덱스 i )/ 2
- 분할 과정: 배열의 가운데 원소를 기준으로 왼쪽과 오른쪽 부분배열로 분할. 탐색키와 가운데 원소가 같으면 가운데 원소의 배열 인덱스를 반환/종료
- 정복 과정: 탐색키가 가운데 원소보다 작으면 왼쪽 부분배열을 대상으로 이진 탐색을 순환 호출, 크면 오른쪽 부분배열을 대상으로 이진 탐색을 순환 호출
- 결합: 필요 없음
작동 원리
다음과 같은 데이터를 정렬하는 과정을 통해 실제 작동 원리를 살펴보자 .
int arr[] = {10, 15, 20, 25, 30, 35, 40, 45, 50}
전체 과정
탐색키가 50일 때를 살펴보자.
i)
10 15 20 25 30 35 40 45 50
이때
left = 0 -> 10
right = 8 -> 50
mid = 4 -> 30
ii)
10 15 20 25 30 35 40 45 50
left = 5 -> 35
right = 8 -> 50
mid = 6 -> 40
iii)
10 15 20 25 30 35 40 45 50
left = 7 -> 45
right = 8 -> 50
mid = 7 -> 45
iV)
10 15 20 25 30 35 40 45 50
left = 8 -> 50
right = 8 -> 50
mid = 8 -> 50
실제 코드 작동을 살펴보자.
시간 복잡도 (성능)
배열 크기 n에 대한 이진 탐색의 최대 분할 횟수와 최대 비교횟수는 어떻게 될까?
n개의 데이터에서 대해서
1) n 번
2) n/2 번
3) n/2^2번
.
.
.
k+1) n/2^k =1
만큼 분할하므로 k= floor(log2n)
최대 비교횟수는 처음 한번을 더해주어 최대 분할횟수 k+1로 볼 수 있다.
따라서 T(n) = 입력 크기 n에 대한 탐색 과정에서의 모든 비교 횟수의 합
= 맨 바깥 수준에서의 비교 횟수 + 순환 호출에서의 비교 횟수
이 점화식을 풀면
T(n) = O(logn)이다.
특징
1. 분할 정복 방식을 이용한다.
2. 입력 데이터가 정렬이 되어 있을 때에만 가능하다.
3. 데이터 정렬 상태를 유지하기 위해 평균 n/2개의 데이터 이동 발생 -> 삽입 삭제가 많은 응용에는 적합하지 않을 수 있다.
자바 구현 코드
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class BinarySearch {
public static void main(String[] args) {
test();
}
@Test
public static void test() {
Assertions.assertEquals(8, binarySearch(new int[] {10, 15, 20, 25, 30, 35, 40, 45, 50}, 0, 8, 50));
}
public static int binarySearch(int[] arr, int left, int right, int target) {
if (left > right) {
return -1; // 탐색 실패 시 -1을 반환
}
int mid = (int)Math.floor((left + right) / 2);
if (target == arr[mid]) {
return mid; // 탐색 성공 시 인덱스 mid를 반환
} else if (target < arr[mid]) {
return binarySearch(arr, left, mid - 1, target); // 왼쪽 부분 배열을 탐색
} else {
return binarySearch(arr, mid + 1, right, target); // 오른쪽 부분 배열을 탐색
}
}
}
'알고리즘 > 기초' 카테고리의 다른 글
버블 정렬 (Bubble Sort) - 아이디어, 작동 원리, 성능 및 시간 복잡도, 특징, 자바 구현 코드 (0) | 2023.06.23 |
---|---|
금액 표기시 천 단위로 숫자에 컴마를 찍는 6가지 방식 (자바 구현 코드) (0) | 2023.06.21 |
자바 숫자의 자릿수를 판별하는 5가지 방식 (1) | 2023.06.21 |
자바 문자열 역순 뒤집기 4가지 방법 (1) | 2023.06.21 |
절대값을 이용한 i, j의 증감 규칙 찾기 (절대값과 나머지를 이용하기) (0) | 2023.06.18 |