JAVA 이진탐색 알고리즘 구성 과정과 장단점
#JAVA006 #이진탐색 #BinarySearch #알고리즘구성과정 #랜덤엑세스순차적엑세스의 차이
Dec 19, 2023
🆕 개요
이진 탐색(Binary Search
)은 정렬된 배열에서 특정한 값을 효율적으로 찾는 검색 알고리즘이다.. 이진 탐색의 기본 원리는 '분할 정복(Divide and Conquer)'이라고 하는데, 이 알고리즘은 중간 지점의 값을 확인하고, 찾고자 하는 값이 중간 값보다 큰지 작은 지를 판단하여 검색 범위를 절반으로 줄여 나가는 방식으로 동작한다이 검색의 장점
은 매우 효율적인 검색 시간이라고 할 수 있다. 이진 탐색은 O(log n)의 시간 복잡도(나중에 따로 설명하겠다.) 를 가지며, 이는 검색 범위가 매 단계마다 절반으로 줄어들기 때문이다. 이러한 특성 덕분에 대규모 데이터 셋에서도 빠른 검색이 가능하다.그러나 단점
은 데이터가 사전에 정렬되어 있어야 한다는 것이다. 정렬되지 않은 데이터 셋에서는 이진 탐색을 직접 적용할 수 없다. 자 그럼 단계별로 이진 탐색의 알고리즘 형성 과정을 살펴보자.
🍇 첫 번째 단계 : 논리 파악
이진 탐색의 논리구조 명료화
- 정렬된 배열이 있다고 가정한다.
- 제일 처음
중간 값을 찾고 비교
한다.
타겟이 중간 값보다 작을 경우
에는끝 지점을 중간 값으로 새로 설정
하고 처음부터 새로 설정된 끝 지점에서 다시 중간 값을 찾는다.- 타겟이 중간 값 보다 작을 경우에는 이 논리가 반복 된다.
타겟이 중간 값보다 클 경우
에는첫 지점을 중간 값으로 새로 설정하
고 새로 설정된 첫 지점에서 기존 끝 지점까지의 구간에서 새로 중간 값을 찾는다.- 타겟이 중간 값 보다 클 경우에는 이 논리가 반복 된다.
기본 요소 코드 작성 1. 예제 배열을 생성 2. 타겟을 설정 3. 배열의 시작 점과 끝 지점 설정
- 0 부터 9까지의 정렬된 배열을 생성하였다.
- 타겟을
8
로 정하고 상수로 선언하였다.
- 배열의 시작 인덱스는
‘0’
이므로start
변수로 초기화하였다.
- 배열의 끝 인덱스는
arr.length - 1
이므로end
변수로 초기화 하였다.
- 그리고 중간 값은 자료 타입만 선언해 두었다.
🍉 두 번째 단계 : 기본 구조 구현
기본 논리 구조 코드 구현
- 중간값은
(시작점 + 끝점) /2
세 가지의 경우가 발생가능
하다.- 중간 값이 타겟과 같은 경우
- 프로그램을 종료하고 안내문구를 출력
- 중간 값이 타겟보다 작은 경우
- 중간 값보다 높은 요소를 검색 해야하므로, 중간 값보다 인덱스가 1보다 높은 곳을 시작점으로 새로 설정한다.
- 중간 값이 타겟보다 클 경우
- 중간 값보다 낮은 요소를 검색 해야하므로, 중간 값보다 인덱스가 1보다 낮은 곳을 끝점으로 새로 설정한다.
코드 작동 확인
- 타겟을 바로 찾았을 때 작동확인
- 타겟이 중간 값보다 작았을 때 확인과
end
값 없데이트 확인
- 타겟이 중간 값보다 클 때 확인과
start
값 업데이트 확인
코드는 모두 잘 작동하고 있다. 이제는 값을 찾을 때 까지 이 논리구조가 반복이 되면 된다. 이제 조건 반복문을 만들어 보자.
🥝 세 번째 단계 : 구조 반복
찾을 때 까지 같은 논리 구조를 반복하기
- 기본 논리 구조는 완성이 되었으므로, 찾을 때까지 같은 구조가 반복이 되면 된다. 이 환경에서는
while
문이 가장 적절하다.
- 찾은 경우에만 반복을 끝낼 수 있도록 타겟과 중간 값이 같은지 비교하는 조건문에
break
를 건다.
- 임의의 숫자를 넣고 한 번 돌려본다.
1회전
에서 중간보다 큰값이 나오고 시작점이 5로 업데이트되었다.
2회전
에서 중간값보다 큰 수중에서의 중간값 (중간중간값??)보다 작은수가 나왔다.
3회전
에서 해당 수를 찾은 모습이다. 즉 코드는 잘 작동한다는 뜻이다.
- 그럼 다른 배열도 한번 대입해보겠다.
다른 수도 대입해보기
- 0부터 14까지의 배열을 생성해본다.
- 임의로 타겟은 4로 정하겠다.
- 돌려보자.
- 4회전만에 4를 찾았다. 잘 작동하는 것 같다!
🍓 결과 : 이진탐색 알고리즘 완성
최종 코드 구현
package ex03.test; public class BinaryTest01 { public static void main(String[] args) { int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; final int target = 3; int start = 0; int end = arr.length - 1; int mid; int round = 0; while (true) { mid = (start + end) / 2; if (arr[mid] == target) { break ; // 값을 찾으면 반복을 종료한다. } if (arr[mid] < target) { start = mid + 1; round++; } if (arr[mid] > target) { end = mid - 1; round++; } } System.out.println("target값은 "+ mid + "이며, 총 " + round + "회전만에 찾았습니다."); } }
- 좀 더 친절하게, 결과 값이랑 몇 회전 만에 찾았는지 안내 문구를 가다듬었다.
- 결과도 잘 작동한다.
- 이진 탐색 알고리즘 완성!
🤔 번외 : 랜덤 엑세스(2진 탐색)가 순차적 엑세스 보다 빠르다??
랜덤 엑세스와 순차적 엑세스의 의미란??
랜덤 엑세스(Random Access)와 순차적 엑세스(Sequential Access)는 데이터에 접근하는 두 가지 기본 방식을 나타낸다. 예를 들어 랜덤 엑세스는 오늘 우리가 공부한 2진 탐색 방식을 말하기도 한다. 그리고 보통 인식으로는 2진 탐색 방식이 순차적 탐색 방식보다 월등히 빠르다고 생각하고들 있다. 근데 과연 그럴까???
2진 탐색의 시간효율성(또는 시간복잡도)은 지수적으로 단축이된다
. 즉 필요한 일부 자료를 방대한 자료속에서 찾게 된다면 자료의 양이 방대할 수록 순차적 탐색방식 보다 빠르다. 예를 들어, 256개의 자료를 찾아야하는 상황에 놓여있다고 가정해 보겠다. 여기서 2진 탐색으로는 log2(256) = 8의 로그스케일로
8번
만에 해당 자료를 찾아낸다. 반면 순차적 접근 방식으로는 256개의 자료를 다 보아야되고, 최악의 경우에는 256번
을 검색해야된다. 바로 여기서 사람들이 인식하는 2진탐색이 순차적 탐색보다 빠르다고 결론을 내리게 되는 이유이다. 과연 항상 이진 탐색방식이 빠를까???
하지만 우리가 찾아야되는 자료가 256개 중에서 40개라고 하면 어떻게 될까?? 여기서 우리는 각 방식의
최악의 시나리오로 시간복잡도를 계산
한다. 이진 탐색으로 1개의 자료를 찾는데 있어서 최악의 시나리오는 8번이고, 여기서
40개를 찾아야 한다면 총 320번
검색이라는 결과가 나온다. 하지만 순차적 탐색 방식은 최악이 256번
이게 되므로 이런 경우에 있어서는 순차적 접근 방식이 더 빠르다 또는 시간복잡도가 낮다라고 말할 수 있는 것이다. 즉,
찾아야하는 자료의 양이 많아 질수록 순차적 접근 방식이 더욱 효율적
인 것이다. 그렇다면 순차적 접근 방식이 효율적이게 되는 순간은 언제부터일까??그렇다면 이진 탐색이 비 효율적이게 되는 변곡점은???
그 지점은
로그수랑 관련이있다
. 총 자료의 양에 이진 로그수를 나누게 된다면 그 지점이 변곡점이다. 찾아야되는 자료의 양이 지수적으로 많아질수록 이진 탐색 방식은 지수적으로 비효율적이 된다. 2의 8승의 자료의 양은 필요한 자료 양이 8분의 1
을 넘기게 되면, 또는 2의 16승의 자료에서 필요한 자료가 16분의 1
을 넘기게 되면 이진 탐색 방식은 비 효율적
이게 된다. 즉, 우리가 금방 예를 든 것과 같이 256개중에서 1회전에 8번의 결과값이라면 32개의 자료를 찾을때 순차적 탐색 방식과 동률이 나오게 된다. 그리고
33개의 자료를 찾는다면 이진 탐색 방식은 순차적 탐색방식보다 효율적이지 못한 것
이라고 할 수 있다. 따라서, 2진 탐색은 순차적 탐색보다 항상 빠르다고 할 수 없는 것이다. 상황에 따라 그리고
필요한 자료의 양에 따라 어떻게 접근하는 것이 효율적인지 잘 파악하고 있어야 된다
고 할 수 있다. Share article