술자리에서 숫자 맞추기 업다운 게임을 할땐 보통 가운데 숫자부터 불러보죠. 그게 바로 이분 탐색입니다.
list.index(x) 메서드도 동일 방식이므로 소요A = [1, 2, 3, 4, 5]
for i in range(A):
if A[i] == 5:
print(i) # 4

함수로 구현하기
n개인 배열 A에서, 값 target을 찾을 때l, r로 둠l = 0, r = n - 1로 초기화(l + r) // 2를 m으로 둠target과 A[m]을 비교A[m] < target인 경우, l을 m + 1로 이동해 검색 범위를 뒤쪽 절반으로 좁힘A[m] > target인 경우, r을 m - 1로 이동해 검색 범위를 앞쪽 절반으로 좁힘A[m] == key인 경우, 인덱스 m을 찾았으니 종료l > r), 배열에 target이 없으니 종료# a에서 target 찾기
def binary_search(a, target):
l = 0 # 검색 범위 맨 앞의 인덱스
r = len(a) - 1 # 검색 범위 맨 끝의 인덱스
while True:
m = (l + r) // 2 # 중앙 원소의 인덱스
if a[m] == target: # target을 찾은 경우
return m
elif a[m] < target: # 인덱스 m 이후에 target 존재
l = m + 1
else:
r = m - 1
if l > r: # 더 이상 검색할 값이 없음
return -1 # 찾지 못한 경우 -1 반환
print()
a = [5, 7, 15, 28, 29, 31, 39, 53, 68, 70, 95]
binary_search(a, 39) # 6

while문이 1번 반복될 때마다 검색 범위가 절반으로 줄어듦bisect 라이브러리파이썬 bisect 라이브러리를 이용해, 직접 함수를 구현하지 않고도 이진 검색을 수행할 수 있음
단, 정렬은 먼저 해 와야 함
bisect.bisect_left(a, x)
a 내 가장 왼쪽 x의 위치를 반환x가 없는 경우, x를 삽입할 수 있는 위치 반환import bisect
a = [1, 4, 7, 7, 10, 13]
print(bisect.bisect_left(a, 7)) # 2 (왼쪽 7의 위치)
print(bisect.bisect_left(a, 11)) # 5 (10과 13 사이)
bisect.bisect_right(a, x)a 내 가장 오른쪽 x의 위치 + 1을 반환x가 없는 경우, x를 삽입할 수 있는 위치 반환import bisect
a = [1, 4, 7, 7, 10, 13]
print(bisect.bisect_right(a, 7)) # 4 (오른쪽 7의 위치 + 1)
print(bisect.bisect_right(a, 11)) # 5 (10과 13 사이)
a 내 x의 원소 개수 구하기bisect_right(a, x) - bisect_left(a, x) 사용 가능가장 오른쪽 x의 위치 + 1 - 가장 왼쪽 x의 위치이므로, x의 원소 개수를 계산 가능import bisect
a = [1, 4, 7, 7, 10, 13]
print(bisect.bisect_right(a, 7) - bisect.bisect_left(a, 7))
# 4 - 2 = 2개
이걸로 이분탐색 꿀빨았습니다.