1. 이진탐색?
- 이진탐색은 정렬되어 있는 선형자료구조에서 사용할 수 있는 탐색 방법이다.
- 정렬되지 않은 자료형의 경우 처음부터 차례대로 값을 비교해야하기 때문에 O(N)의 시간복잡도를 갖는다.
- 반면 자료가 정렬되어 있는 경우 이진탐색을 통해 O(logN)의 시간복잡도로 값을 찾을 수 있다.
- 이진탐색은 범위를 주면 해당 범위 중간값을 기준으로 찾고자 하는 값이 중간값보다 큰지 작은지를 판단하는 방법이다.
- ex) 책에서 원하는 페이지 번호를 찾으려 할 때 일단 책을 펴고 찾고자 하는 페이지 번호가 더 작으면 앞부분을,
찾고자 하는 페이지 번호가 더 크면 뒷부분을 보는 것과 같다.
2. 이진탐색 알고리즘
- 찾고자 하는 값을 target이라 한다
- 리스트 nums가 주어지면 가장 작은 인덱스를 left, 가장 큰 인덱스를 right라 하여 범위를 지정한다.
- left와 right의 중간 인덱스를 mid라 하고 nums[mid]와 target과 비교한다.
- nums[mid]가 target보다 크다면 left = mid + 1 ~ right 까지 범위에서 이진탐색을 다시 시행한다.
- nums[mid]가 target보다 작다면 left ~ right = mid - 1 까지 범위에서 이진탐색을 다시 시행한다.
- target을 발견했다면 해당하는 인덱스를 반환한다.
- target을 발견하지 못했다면 -1을 반환한다.
2 - 1) 이진탐색을 성공하는 경우
target인 22보다 nums[mid]가 작으므로 left = mid + 1인 범위부터 다시 탐색한다
앞에서부터 차례대로 탐색하는 순차탐색의 경우 6번 비교해서 찾을 것을 2번만에 찾을 수 있게 된다
한 번 탐색할 때마다 탐색할 범위가 절반씩 사라지므로 자료의 개수가 커져도 연산 횟수가 크게 늘어나지 않는다(O(logN) 시간복잡도)
2 - 2) 이진탐색을 실패하는 경우
left의 값이 right의 값보다 커지게 되고 탐색은 종료된다
3. Python 구현
3 - 1) 반복문을 사용
def BinarySearch(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
return mid
return -1
3 - 2) 재귀를 사용
def BinarySearch(nums, target):
def _search(left, right):
if left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
return _search(mid + 1, right)
elif nums[mid] > target:
return _search(left, mid - 1)
else:
return mid
return -1
return _search(0, len(nums) - 1)
- left와 right를 비교할 때 등호가 헷갈릴 수 있는데 이진탐색의 경우 같은 left와 right가 같아지는 경우도 비교를 해야하므로 등호를 넣어준다
3 - 3) bisect module
from bisect import bisect_left
def BinarySearch(nums, target):
idx = bisect_left(nums, target)
if idx < len(nums) and nums[idx] == target:
return idx
return -1
bisect 모듈의 bisect_left를 사용해 이진탐색을 수행할 수 있다.
bisect_left는 lower bound를 수행하는 함수이다.
nums와 target이 파라미터로 주어지면 nums 안에서 target 이상이되는 최솟값을 반환하는 함수이다.
nums 안에 target이 존재한다면 idx는 target의 인덱스가 되고 target이 존재하지 않는다면 target의 인덱스보다 큰 값이 idx에 저장된다. nums[idx]와 target을 비교하여 둘이 같은 경우만 idx를 반환하면 이진 탐색을 수행할 수 있다.
bisect_left와 bisect_right에 대해서는 다음에 같이 다뤄보려 한다.
'CS > 알고리즘' 카테고리의 다른 글
배수판정법 (1) | 2023.01.10 |
---|---|
[Python] lower bound, upper bound 구현 (0) | 2022.07.06 |
[Python] 피보나치 수열과 Dynamic Programming 기초 (0) | 2022.03.19 |
[Python] bisect 라이브러리 (lower bound, upper bound) (0) | 2022.03.19 |
정렬 (0) | 2020.10.25 |