알고리즘

Binary Search (이진 탐색)

fenec_fox 2024. 4. 30. 17:09

이진 탐색(Binary Search)은 정렬된 배열에서 원하는 값을 시간복잡도 O(log N) 만에 찾아내는 탐색하는 방법입니다.

오름차순으로 정렬된 사이즈가 N인 배열 D에서 원하는 값 k(k = 11)를 찾는 방법은 다음과 같습니다.

먼저 탐색할 데이터의 범위를 두 개의 인덱스(왼쪽, 오른쪽)로 지정하고 이를 L, R이라고 하겠습니다. 정렬되어있기 때문에 D[L]은 최솟값, D[R]은 최대값이 됩니다.

L     M       R
0 1 2 3 4 5 6 7
-3 0 1 4 7 9 11 16

당연히 처음 탐색 시에는 전체영역이므로 L = 0, R = N - 1 입니다. 이중 중앙값(Median)을 찾아 찾으려는 값 k와 비교합니다. 중앙값 M은 (L+R)/2 로 구할 수 있습니다.
중앙값인 D[M]과 K를 비교하였을 시, K가 더 크므로 [0, M]범위에는 K값이 존재할 수 없습니다. 그러므로 L을 M+1로 옮겨주어 [M+1,R] 사이에서 K값을 찾도록 해보겠습니다.

        L M   R
0 1 2 3 4 5 6 7
-3 0 1 4 7 9 11 16

아직도 D[M]이 K보다 작기 때문에, L을 M+1로 옮겨주겠습니다.

            L / M R
0 1 2 3 4 5 6 7
-3 0 1 4 7 9 11 16

D[M]이 K와 같으므로 원하는 값을 찾았습니다.

이와 같이, 중앙값(D[M])과 찾으려는 값을 비교하여 찾으려는 값이 중앙값보다 크다면 L = M + 1, 작다면 R = M - 1을 한 후 다시 M을 구하는 방법으로 찾으려는 값이 없는 범위를 절반씩 잘라가면서 구하는 방법이 이진 탐색입니다.

만약 찾으려는 값이 없다면 L > R이 되어서 종료하면 됩니다. 이 경우에도, 최대한 찾으려는 값과 비슷한 값들을 찾아가기 때문에, 이 점 또한 유용하게 사용하실 수 있습니다.

이 알고리즘의 시간복잡도는 쿼리당 O(log N)으로 빠른 알고리즘입니다. 정렬 알고리즘 또한 힙정렬이나 퀵정렬 등의 빠른 알고리즘을 사용하시면 더 효율적입니다.

다음은 C++로 나타낸 코드입니다.

더보기
#include <iostream>
#include <algorithm>

#define MAX 5005

int d[MAX], n;

bool bsearch(int val){

	int l = 0, r  = n - 1;

	while(l <= r){
		int mid = (l+r)/2;

		if(val == d[mid]) return true;
		else if(val > d[mid]) l = mid + 1;
		else r = mid - 1;
	}

	return false;
}

int main() {
	scanf("%d", &n);

	for (int i = 0; i < n; i++)
		cin >> d[i];

	sort(d, d + n);

	int query;

	cin >> query;

	while (query--) {
		int x; cin >> x;

		if (bsearch(x)) cout << "exist" << endl;
		else cout << "not exist" << endl;
	}
}

다음은 Java로 나타낸 코드입니다.

더보기
import java.util.*;

public class Main {
    public static void main(String args[]) {
        Scanner scanner = new Scanner(System.in);

        int n = scanner.nextInt();
        int[] d = new int[5005];
        for (int i = 0; i < n; i++)
            d[i] = scanner.nextInt();

        // bubble sorting
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n - i - 1; j++)
                if (d[j] > d[j + 1]) {
                    int temp = d[j];
                    d[j] = d[j + 1];
                    d[j + 1] = temp;
                }

        // binary search for each query
        int query = scanner.nextInt();
        for (int i = 0; i < query; i++) {
            int x = scanner.nextInt();
            int l = 0, r = n - 1;
            boolean answer = false;

            while (l <= r) {
                int mid = (l + r) / 2;
                if (x == d[mid]) {
                    answer = true;
                    break;
                }
                else if (x > d[mid]) l = mid + 1;
                else r = mid - 1;
            }

            if (answer == true) System.out.println("exist");
            else System.out.println("not exist");
        }
    }
}