4.1 선형 탐색과 이진 탐색의 시간 복잡도 비교
선형 탐색과 이진 탐색의 시간 복잡도를 비교해보자.
선형 탐색:
- 시간 복잡도:
O(n), 여기서n은 배열이나 리스트의 요소 개수야. - 최선의 경우:
O(1)— 첫 번째 위치에서 요소가 발견됨. - 평균적인 경우:
O(n/2) = O(n)— 요소가 평균적으로 중간 어딘가에서 발견됨. - 최악의 경우:
O(n)— 요소가 마지막에 있거나 없을 때.
이진 탐색:
- 시간 복잡도:
O(log n), 여기서n은 배열이나 리스트의 요소 개수야. - 최선의 경우:
O(1)— 첫 번째 단계에서 요소가 발견됨 (중간 요소). - 평균적인 경우:
O(log n)— 정렬된 배열에서의 탐색. - 최악의 경우:
O(log n)— 마지막 단계에서 요소가 발견되거나 없을 때.
시간 복잡도 분석 예시
선형 탐색:
- 배열
[1, 3, 5, 7, 9, 11, 13], 찾고자 하는 요소 7. - 인덱스 3에서 7을 찾을 때까지 각 요소를 검사함.
- 4회 검사가 필요했고, 이는
O(n)에 해당해.
이진 탐색:
- 배열
[1, 3, 5, 7, 9, 11, 13], 찾고자 하는 요소7. - 첫 번째 단계에서 중간 요소(7)가 발견됨.
- 1회 검사가 필요했고, 이는
O(log n)에 해당해.
4.2 각각의 방법의 장단점
각 탐색 유형의 장단점을 살펴보자.
선형 탐색:
장점:
- 구현의 간단함: 선형 탐색은 매우 쉽게 구현하고 이해할 수 있어.
- 데이터 요구사항 없음: 정렬되지 않은 데이터에도 사용할 수 있어.
- 작은 배열에 적합: 작은 배열에서는 효율적이야.
단점:
- 큰 배열에서 비효율적:
O(n)시간 복잡도로 인해 효과적이지 않음. - 긴 실행 시간: 큰 배열에서 끝 또는 없음에 근접한 요소를 찾을 때 시간이 많이 걸릴 수 있어.
이진 탐색:
장점:
- 큰 배열에서의 높은 효율성:
O(log n)시간 복잡도로 매우 효율적이야. - 빠른 수행: 큰 정렬된 배열에서 선형 탐색보다 훨씬 빠름.
단점:
- 정렬된 데이터 필요: 정렬된 배열에서만 작동하므로, 사전 정렬에 추가 시간이 필요할 수 있어.
- 구현의 복잡함: 선형 탐색에 비해 구현이 복잡해.
4.3 언제 어떤 탐색을 사용할까
선형 탐색을 언제 사용하고, 이진 탐색을 언제 사용해야 하는지 알아보자.
선형 탐색.
다음과 같은 경우 선형 탐색을 사용해:
- 배열이나 리스트가 정렬되지 않은 경우.
- 배열이나 리스트의 크기가 작은 경우.
- 정렬에 추가 비용 없이 간단하고 빠른 솔루션이 필요한 경우.
- 첫 번째 발견 혹은 모든 발견이 필요한 경우.
- 실시간으로 데이터가 들어와서 사전 정렬이 불가능하거나 비효율적인 경우.
이진 탐색.
다음과 같은 경우 이진 탐색을 사용해:
- 배열이나 리스트가 정렬된 경우.
- 배열이나 리스트의 크기가 큰 경우.
- 동일한 데이터 세트에서 자주 탐색이 필요한 경우 (한 번 데이터를 사전 정렬할 수 있음).
- 탐색 속도가 중요한 경우.
- 데이터 사전 정렬에 시간 투자할 가치가 있는 경우.
4.4 선형 탐색 문제 예시
1. 정렬되지 않은 리스트 탐색
정렬되지 않은 숫자 리스트에서 주어진 숫자의 인덱스를 찾아야 해.
예시:
def linear_search(arr, target):
for index, element in enumerate(arr):
if element == target:
return index
return -1
arr = [4, 2, 7, 1, 9, 3]
target = 7
print(linear_search(arr, target)) # 출력: 2
2. 배열의 첫 번째 발생 문제
주어진 요소가 문자열 리스트에서 처음 발생하는 위치를 찾아야 해.
예시:
def linear_search(arr, target):
for index, element in enumerate(arr):
if element == target:
return index
return -1
words = ["apple", "banana", "cherry", "date", "banana"]
target = "banana"
print(linear_search(words, target)) # 출력: 1
3. 실시간 데이터 탐색
실시간으로 들어오는 데이터 스트림에서 요소를 찾아봐.
예시:
import random
def find_in_stream(stream, target):
for index, element in enumerate(stream):
if element == target:
return index
return -1
stream = [random.randint(1, 100) for _ in range(100)]
target = 50
print(find_in_stream(stream, target))
4.5 이진 탐색 문제 예시
1. 정렬된 배열 탐색
정렬된 숫자 배열에서 주어진 숫자의 인덱스를 찾아봐.
예시:
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
sorted_array = [1, 3, 5, 7, 9, 11, 13]
target = 7
print(binary_search(sorted_array, target)) # 출력: 3
2. 큰 데이터 세트에서의 빈번한 탐색
큰 정렬된 숫자 배열에서 요소를 자주 찾아야 해.
예시:
import random
sorted_large_array = sorted([random.randint(1, 1000000) for _ in range(1000000)])
target = random.choice(sorted_large_array)
print(binary_search(sorted_large_array, target))
3. 정렬된 데이터베이스 요소 탐색
키 필드로 정렬된 데이터베이스에서 레코드를 찾아봐.
예시:
database = sorted([{"id": i, "value": f"record_{i}"} for i in range(100000)])
def binary_search_db(db, target_id):
left, right = 0, len(db) - 1
while left <= right:
mid = (left + right) // 2
if db[mid]["id"] == target_id:
return db[mid]
elif db[mid]["id"] < target_id:
left = mid + 1
else:
right = mid - 1
return None
target_id = 54321
print(binary_search_db(database, target_id))
GO TO FULL VERSION