Algorithm ( 알고리즘 )

이분검색(Binary Search) - Java구현

비뀨_ 2023. 2. 19. 23:01

이분검색은 검색할 범위를 반으로 줄여가며 답을 찾아가는 알고리즘이다.

 

이분검색

말로하면 지루하니까 미천한 그림판실력을 발휘해보겠다.

 

다음과 같이 오름차순으로 정렬된 배열이 있다고 생각해보자.

우리는 여기서 1이 몇번째에 있는지 바로 알 수 있지만 컴퓨터는 그렇지 못하다.

 

이분 검색의 절차를 그려보자면 아래와 같다.

  • 배열의 정 가운데 요소를 기준으로 반으로 쪼갠다.
  • 1이 가운데의 원소인 9보다 작으면 왼쪽 배열을 선택한다.
  • 왼쪽 배열의 가운데 요소 3을 기준으로 쪼갠다
  • 1이 가운데 원소인 3보다 작으면 왼쪽배열을 선택한다.
  • 1이 남았다. 찾으려는 값이 1이기 때문에 종료한다.

 

이분검색은 분할정복 알고리즘 중 가장 간단한 부류에 속한다. 왜냐면 입력사례를 분할해 해답을 구하고, 결과를 취합할 필요가 없기 때문이다.

 

분할정복으로 재귀 알고리즘을 개발할 때 아래의 사항들을 꼭 고려해야한다!

  • 작은 입력사례의 답으로 전체 입력사례의 답을 구하는 방법을 고안
  • 더 이상 분할이 불가능한 입력사례를 판단할 종료조건을 정한다.
  • 종료조건을 만족하는 경우 답을 어떻게 구하는지 정한다.

내 실습을 위해서 Java로 구현하는 예제를 만들어보겠다.

 

재귀 방식을 이용한 이분 검색

    public static int recursion(int[] arr, int findNumber, int low, int high) {
        if(low > high) return -1; // 마지막까지 갔을 때 찾을수 없다라는 값인 -1 반환
        int mid = low + (high - low) / 2;
        if(arr[mid] == findNumber) {
        	return mid; // 찾는 값일 때 해당 번째 반환
        }
        else if (arr[mid] < findNumber) { // 찾는 값보다 작을 때는 중간값보다 오른쪽에 있음
            return recursion(arr, findNumber, mid + 1, high); 
        }else {
            return recursion(arr, findNumber, low, mid - 1); // 반대로 중간값보다 왼쪽에 있음
        }
    }
    
    public static void main(String[] args) {
        int[] arr = {1, 3, 6, 9, 13, 17, 20, 26};
        int find = 13;
        int result = recursion(arr, find, 0, arr.length - 1);

        System.out.println(find + "은(는) 배열의 " + result + "번째에 있습니다.");
    }

다른 예제로 재귀 방식이 아니라 이분 검색을 구현해보자

public static int binarySearch(int[] arr, int findNumber) {
    int low = 0; // 처음의 항목은 0으로 고정
    int high = arr.length - 1; // 마지막 항목은 arr.length -1 번째에 위치
	
    while(low <= high) {
        int mid = low + (high - low) / 2; // 인덱스의 중간 값
        
        // 중간 값이 찾는 값과 같다면 정답임
        if(arr[mid] == findNumber) {
            return mid;
        }
        // 중간 값이 찾는 값보다 작으면 mid보다 큰 쪽에 위치하게 됨.
        // 반대로 중간 값이 작으면 mid보다 작은 쪽에 위치하게 됨
        if(arr[mid] < findNumber) {
            low = mid + 1;
        }else {
            high = mid - 1;
        }
    }
    return -1;
}

public static void main(String[] args) {
    int[] arr = {1, 3, 6, 9, 13, 17, 20, 26};
    int find = 1;
    int result = binarySearch(arr, find);

    System.out.println(find + "은(는) 배열의 " + result + "번째에 있습니다.");
}

이해하기 어려운 코드는 아닐거라고 생각한다.

 

재귀와 반복문을 통한 이분 검색 공통으로 설명할 수 있는 실행 순서를 그림으로 보자

아래 이미지를 순서대로 보자.

  • 처음의 low는 0, mid는 3, high는 7이다
  • 찾으려는 값인 1은 9보다 왼쪽에 있기 때문에 high를 앞으로 당겨줘야 한다.
    • 코드에서 high를 mid -1 로 하는 이유는 이미 9는 본 값이기 때문에 굳이 9를 또 가진 배열일 필요가 없기 때문이다.
  • 위의 행동을 반복하면 결국 mid가 배열의 0번째인 1이 된다.
  • 반환한다
  • 만약 값이 없으면 -1을 반환한다.

 

이분검색의 시간 복잡도

이분 검색의 시간 복잡도는 O(log n) 이다.

만약 배열의 길이가 32개라면 5번만에 찾을 수 있고,

1024개라면 10번의 식으로 2의 n 제곱마다 1번씩 증가한다.

 

중요!

이분검색은 기본 조건이 정렬된 배열을 가지고 검색해야 한다.

 

'Algorithm ( 알고리즘 )' 카테고리의 다른 글

백준 2750번 문제 ( 정렬하기 )  (0) 2021.10.17