본 글에 사용된 코드와 이미지의 일부는
딩코딩 님의 『38군데 합격 비법, 2025 코딩테스트 필수 알고리즘』 강의를 참조하여 발췌·활용하였습니다.[본 게시물은 파트너스 활동의 일환으로 소정의 수수료를 받을 수 있습니다.] https://inf.run/tXMrp\
이진 탐색 vs 순차 탐색
특정 숫자를 맞추는 게임인 업다운 게임을 생각해보자. 가장 좋아하는 숫자, 끌리는 숫자, 1부터 차근차근 등 특정 숫자를 맞추는데 다양한 방식이 있을 것이다.
알고리즘 관점에서 보면 가장 효율적인 방법은 범위의 절반인 50을 시도 해보는 것이다. 대답이 UP 이라면 1~49 는 후보에서 없어지고, 대답이 DOWN 이면 51~100 이 후보에서 없어진다.
이 방법을 이진 탐색이라고 한다.
순차 탐색
그러면 순차 탐색과 이진 탐색 중 어느 방식이 더 효율적일까?
우선 순차 탐색의 코드를 살펴보자.
finding_target = 14
finding_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
def is_existing_target_number_sequential(target, array):
find_count = 0
for number in array:
find_count += 1
if target == number:
print(find_count) # 14!
return True
return False
result = is_existing_target_number_sequential(finding_target, finding_numbers)
print(result) # True
배열을 차례로 따라가면서 찾다보니, 검색 횟수가 총 14번이 나온다. 만약 찾는 숫자가 20 이였다면, 20번 검색해야 했을테니, 최악의 경우는 O(N) 걸린다고 할 수 있다.
이진 탐색
그럼 이진 탐색을 살펴보자.
finding_target = 14
finding_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
def is_existing_target_number_binary(target, array):
current_min = 0
current_max = len(array) - 1
current_guess = (current_min + current_max) // 2
find_count = 0
while current_min <= current_max:
find_count += 1
if array[current_guess] == target:
print(find_count) # 3!
return True
elif array[current_guess] < target:
current_min = current_guess + 1
else:
current_max = current_guess - 1
current_guess = (current_min + current_max) // 2
return False
result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)
만약 UP 이라면? 9 ~ 16을 시도하고, 만약 DOWN 이라면? 1 ~ 7을 시도하고, 만약 정답이라면? True 를 반환하면 된다.
위와 같이 하기 위해서는 최솟값, 최댓값, 시도하는 인덱스 값 을 변수로 설정하면 된다. 그리고 시도했을 때 target 보다 작다면, 더 큰 값을 살펴봐야 하니까 최솟값에 시돗값 + 1 을 해주면 된다. target 보다 크다면, 더 작은 값을 살펴봐야 하니까 최댓값에 시돗값 - 1 을 해주면 된다. 이를 최솟값≤ 최댓값 까지 반복해야 한다. < 가 아니라 ≤ 인 이유는 최솟값 == 최댓값 시점까지 확인을 해야 하기 때문이다.
이진 탐색의 시간 복잡도
총 숫자가 1 ~ N 까지라고 한다면 1번 탐색 → N/2 , 2번 탐색 → N/4 , 3번 탐색 → N/8 … k번 탐색 → N/2^k 개가 남게 된다.
이 때, 이분 탐색을 열심히 시도해서 딱 1개만 남았다고 해보자. 수식으로 표현하면 N/2^k = 1 이다.
즉, $k = \log_2{N}$ 횟수를 시도하면 정답을 찾을 수 있다. 결론적으로 이분 탐색을 위해서는 시간 복잡도가 O(log N) 만큼 걸린다.
여기서 왜 $log_2N$ 이 아니라 $logN$ 인 이유는 상수는 무시해도 되기 때문에 표기하기 쉽도록 $logN$ 으로 약속했다.
'인프런 > 딩코딩코 알고리즘' 카테고리의 다른 글
| [딩코딩코 2025 코딩테스트 필수 알고리즘] - 8. 버블 정렬 (0) | 2025.09.03 |
|---|---|
| [딩코딩코 2025 코딩테스트 필수 알고리즘] - 7. 재귀함수 (1) | 2025.09.01 |
| [딩코딩코 2025 코딩테스트 필수 알고리즘] - 5. LinkedList 구현 (2) | 2025.08.28 |
| [딩코딩코 2025 코딩테스트 필수 알고리즘] - 4. Array & LinkedList (1) | 2025.08.28 |
| [딩코딩코 2025 코딩테스트 필수 알고리즘] - 3. 점근 표기법 (0) | 2025.08.24 |