Python 이진탐색 알고리즘
1~100 사이에서 숫자 하나를 맞춰야 한다면 알고리즘의 관점에선 가장 효율적인 방법은 범위의 절반인 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_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)
return True
elif array[current_guess] < target:
current_min = current_guess +1 #최솟값을 시도값 +1로 변경 / 다운은 최댓값을 시도값 -1로 변경
else:
current_max = current_guess -1
current_guess = (current_max + current_min) // 2 # 새롭게 current_guess를 업데이트
return False # 한번도 발견되지 않았다면 return False
result = is_existing_target_number_binary(finding_target, finding_numbers)
print(result)
16에서 14를 찾는다.
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
함수가 실행되면,
최소, 최대 값의 변수를 만든다. 최대값을 설정할 때는 array로 넘어온 자료가 리스트이기 때문에 0부터 시작하니 범위에서 1만큼 빼준다.
추측하는 값인 current_guess를 최대값 + 최소값 // 2로 변수를 만든다.
소숫점은 필요없기 떄문에 //를 사용한다.
find_count는 순차탐색과 비교하기 위해서 넣은 변수다.
while current_min <= current_max:
find_count += 1
if array[current_guess] == target:
print(find_count)
return True
elif array[current_guess] < target:
current_min = current_guess +1 #최솟값을 시도값 +1로 변경 / 다운은 최댓값을 시도값 -1로 변경
else:
current_max = current_guess -1
current_guess = (current_max + current_min) // 2 # 새롭게 current_guess를 업데이트
return False # 한번도 발견되지 않았다면 return False
while문을 돌린다.
최소값이 최대값보다 작을 경우 계속해서 돌아간다. 어차피 최소값이 최대값보다 작거나 같아지기 전에 타겟넘버를 찾기 때문이다.
find_count 는 순차탐색과 비교하기 위해 넣은 연산자다.
만약 array의 current_guess 번 째 인덱스가 target과 같다면
바로 True를 반환해주고 함수를 끝낸다.
elif
만약 current_guess번째 인덱스가 target보다 작다면,
최소값 설정을 추측값에서 +1만큼 해준다.
ex) 1~16에서 14를 찾아야하는데. 처음엔 8이 나올 것.
그럼 최소값은 8에서 +1한 9값이 될 것이다. 어차피 8이 아니었으니까 +1해서 다시 9~16만큼의 이분탐색으로 들어가는 것이다.
else
다른 경우라면 current_guess번째 인덱스가 target보다 클 경우인데, 이때는 최대값을 추측값에서 -1만큼 빼준다.
ex) 1~16에서 5를 찾아야하는데, 8이 나왔을 경우는, 최소값은 그대로 두고 최대값만 7로 설정해서, 1~7사이에서 타겟넘버를 찾는 것이다.
if, elif, else문이 끝나면 current_guess 즉 추측값을 새로 설정된 최대값과 최소값을 더해 2로 나눈다.
그리고 다시 while문으로 돌아간다.
만약 이 과정에서 타겟넘버가 한 번도 발견되지 않았다면 False를 리턴한다.
순차탐색과의 비교
finding_target = 14
finding_numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
# O(N)
def is_existing_target_number_sequential(target, array):
find_count = 0
for number in array:
find_count +=1
if target == number:
print(find_count)
return True
return False
result = is_existing_target_number_sequential(finding_target, finding_numbers)
print(result) # True
똑같이 1~16사이에 14를 찾는 과정인데,
14를 찾기 까지 총 14번의 fint_count가 확인되고
이분탐색은 14를 찾기까지 총 3번의 fint_count를 확인할 수 있다.
이분탐색이 좀 더 효율적인 것을 알 수 있다.
'Back > Algorithm' 카테고리의 다른 글
Python 백준 11651 좌표정렬하기2 / 파이썬 알고리즘 (0) | 2021.03.09 |
---|---|
Python 재귀함수 알고리즘 - 백준 11729 하노이탑 (0) | 2021.03.09 |
Python 재귀함수 알고리즘 Factorial, 회문 검사 (0) | 2021.03.09 |
백준 알고리즘 4344 파이썬 (0) | 2021.03.07 |
백준 알고리즘 4673 파이썬 (0) | 2021.03.06 |