CS

[알고리즘] 이진 탐색(Binary Search)

danii0110 2024. 12. 8. 19:13

이진 탐색(Binary Search)이란?

  • 정의: 이진 탐색은 정렬된 배열에서 값을 찾는 알고리즘으로, 검색 범위를 절반씩 좁혀가며 값을 탐색한다.
  • 특징
    - 배열 또는 리스트가 정렬되어 있어야 한다.
    - 탐색 범위를 매번 절반으로 줄이므로 매우 빠르다.
  • 장단점
    - 장점
       - 정렬된 데이터에서 매우 빠름
       - O(log n)의 시간 복잡도로 대용량 데이터 처리 가능
    - 단점
       - 데이터가 반드시 정렬되어 있어야 함
       - 재귀 방식에서는 스택 오버플로우 위험

이진 탐색의 동작 원리

1. 시작점(Start)과 끝점(End)을 설정한다.

 

2. 중간점(Mid)을 계산한다: Mid = (Start + End) / 2

 

3. 중간점의 값과 목표값(Target)을 비교한다.

  • 중간점 값  == 목표값 -> 검색 성공
  • 중간점 값 < 목표값 -> 검색 범위를 오른쪽 절반으로 좁힘
  • 중간점 값 > 목표값 -> 검색 범위를 왼쪽 절반으로 좁힙

 

4. 위 과정을 목표값을 찾거나 검색 범위가 없을 때까지 반복한다.


이진 탐색의 구현 방법

1. 반복문(Iterative) 방식

public int binarySearch(int[] arr, int target) {
    int start = 0;
    int end = arr.length - 1;

    while (start <= end) {
        int mid = start + (end - start) / 2; // 중간점 계산
        if (arr[mid] == target) {
            return mid; // 목표값 찾음
        } else if (arr[mid] < target) {
            start = mid + 1; // 오른쪽 탐색
        } else {
            end = mid - 1; // 왼쪽 탐색
        }
    }
    return -1; // 목표값이 없음
}

 

 

2. 재귀(Recursive) 방식

public int binarySearchRecursive(int[] arr, int target, int start, int end) {
    if (start > end) {
        return -1; // 목표값 없음
    }
    int mid = start + (end - start) / 2;
    if (arr[mid] == target) {
        return mid; // 목표값 찾음
    } else if (arr[mid] < target) {
        return binarySearchRecursive(arr, target, mid + 1, end); // 오른쪽 탐색
    } else {
        return binarySearchRecursive(arr, target, start, mid - 1); // 왼쪽 탐색
    }
}

 


시간 복잡도와 공간 복잡도

  • 시간 복잡도
    - O(log n): 매번 탐색 범위를 절반으로 줄이기 때문
  • 공간 복잡도
    - 반복문 방식: O(1) (추가 공간 필요 없음)
    - 재귀 방식: O(log n) (재귀 호출 스택 사용)

이진 탐색의 활용 예시

1. 배열에서 특정 값 찾기

  • 정렬된 배열에서 빠르게 값을 찾음

2. Lower Bound와 Upper Bound

  • Lower Bound: 특정 값 이상인 첫 번째 위치 찾기
  • Upper Bound: 특정 값보다 큰 첫 번쨰 위치 찾기

3. 코딩 테스트 활용 사례

  • 두 배열의 합: 특정 합을 이루는 쌍 찾기
  • K번째 원소 찾기: 정렬된 배열에서 K번쨰 값을 찾음
  • 최적화 문제: 범위를 좁히며 최적의 값을 찾음

Lower Bound와 Upper Bound 구현 예제

1. Lower Bound 구현

public int lowerBound(int[] arr, int target) {
    int start = 0, end = arr.length;
    while (start < end) {
        int mid = start + (end - start) / 2;
        if (arr[mid] >= target) {
            end = mid;
        } else {
            start = mid + 1;
        }
    }
    return start;
}

 

 

2. Upper Bound 구현

public int upperBound(int[] arr, int target) {
    int start = 0, end = arr.length;
    while (start < end) {
        int mid = start + (end - start) / 2;
        if (arr[mid] > target) {
            end = mid;
        } else {
            start = mid + 1;
        }
    }
    return start;
}

 


이진 탐색과 선형 탐색의 비교

구분 이진 탐색(Binary Search) 선형 탐색(Linear Search)
시간 복잡도 O(log n) O(n)
데이터 정렬 필요성 정렬 필요 정렬 불필요
속도 매우 빠름 느림