모눈종이에 사각사각

이진 탐색, 이진 탐색 트리 본문

Algorithm

이진 탐색, 이진 탐색 트리

모눈종이씨 2021. 9. 12. 16:01

이번 포스팅에서는 이진 탐색 알고리즘에 대해 설명하고자 한다.

이진 탐색에 대해 설명하기 전에 먼저 순차 탐색에 대해 알아보자

🍀 [순차 탐색 Sequential Search]

순차 탐색은 말그대로 앞에서부터 순차적으로 하나씩 확인하며 탐색하는 것이다. 보통 정렬되지 않은 리스트에서 데이터를 찾아야 할 때 사용한다.

따라서 시간복잡도는 \(O(N)\)이다.

🍀 [이진 탐색 Binary Search]

이진 탐색은 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 것이다.

배열 내부의 데이터가 정렬되어 있을 때만 사용할 수 있으며, 

정렬 되어 있을 경우, 빠르게 데이터를 찾을 수 있다는 장점이 있다.

 

이진 탐색은 변수를 3개 사용한다.

1. 시작점
2. 끝점
3. 중간점

 

찾으려는 데이터와 중간점 위치에 있는 데이터를 반복적으로 비교해서 원하는 데이터를 찾는다.

- 중간점과 찾고자 하는 값을 비교한다.

 

- 만약 찾고자 하는 값보다 중간점이 클 경우, 중간점 이후의 값은 확인할 필요가 없다.

    -> 끝점을 중간점 하나 앞으로 옮기고, 중간점을 다시 세팅한다.

 

- 만약 찾고자 하는 값보다 중간점이 작을 경우, 중간점 이전의 값은 확인할 필요가 없다.

    -> 시작점을 중간점 하나 뒤로 옮기고, 중간점을 다시 세팅한다. 

 

한 번 확인 할 때마다 확인하는 원소의 개수가 평균적으로 절반씩 줄어들기 때문에 연산 횟수는 \(log_2N\)에 비례한다고 할 수 있고, 시간복잡도는 \(O(logN)\)이다.

 

코딩 테스트의 이진 탐색 문제는 탐색 범위가 큰 상황에서의 탐색을 가정하는 문제가 많다.

탐색 범위가 2,000만을 넘어가면 이진 탐색으로 문제에 접근해 보길!

🍀 [이진 탐색 구현]

1. 재귀 함수로 구현

def binary_search(array, target, start, end)::
	# 시작점이 끝 점보다 큰 경우, 
    # 찾고자 하는 값이 없어 교차된 것임
    if start > end:
    	return None

	# 중간점 설정
	mid = (start+end)//2
    
    # 찾은 경우 중간점 인덱스 반환
   	if array[mid] == target:
    	return mid
    
    # 중간점의 값이 찾고자 하는 값보다 클 경우
    # 오른쪽을 버리고 끝점을 옮겨옴.
    elif array[mid] > target:
    	return binary_search(array, target, start, mid-1)
    
    # 중간점의 값이 찾고자 하는 값보다 작을 경우
    # 왼쪽을 버리고 시작점을 옮겨옴.
    else:
    	return binary_search(array, target, mid+1, end)

# 입력
n = 10
target = 7
array = [1,3,5,7,9,11,13,15,17,19]

reslut = binary_search(array, start, target, 0, n-1)
if reslut == None:
	print("원소가 존재하지 않습니다.")
else:
	print(reslut+1)

2. 반복문으로 구현

def binary_search(array, target, start, end):
	
    # 시작점이 끝 점보다 작을 때만 반복문 돎
    while start<=end:
    
        # 중간점 설정
        mid = (start+end)//2
    
        # 찾은 경우 중간점 인덱스 반환
        if array[mid] == target:
            return mid
    
        # 중간점의 값이 찾고자 하는 값보다 클 경우
        # 오른쪽을 버리고 끝점을 옮겨옴.
        elif array[mid] > target:
            end = mid-1
    
        # 중간점의 값이 찾고자 하는 값보다 작을 경우
        # 왼쪽을 버리고 시작점을 옮겨옴.
        else:
            start = mid+1
 	
    return None

# 입력
n = 10
target = 7
array = [1,3,5,7,9,11,13,15,17,19]

reslut = binary_search(array, start, target, 0, n-1)
if reslut == None:
	print("원소가 존재하지 않습니다.")
else:
	print(reslut+1)

🍀 [이진 탐색 트리]

이진 탐색 트리란?

이진 탐색이 동작할 수 있도록 고안된, 효율적인 탐색이 가능한 자료구조

 

특징으로는 왼쪽 자식 노드 < 부모 노드 < 오르쪽 자식 노드 라는 것이다.

루트 노드부터 방문하여 찾고자 하는 값보다 루트 값이 크면 왼쪽자식 노드로 내려가서 탐색하면 되는 것이고,

찾고자 하는 값보다 루트 값이 작으면 오르쪽 자식 노드로 내려가서 탐색하면 되는 것이다.

🍀 [파이썬 이진 탐색 라이브러리]

- bisect_left(a, x) : 정렬된 순서를 유지하면서 배열 a에 x를 삽입할 가장 왼쪽 인덱스를 반환

- bisect_right(a, x) : 정렬된 순서를 유지하면서 배열 a에 x를 삽입할 가장 오른쪽 인덱스를 반환

from bisect import bisect_left, bisect_right

a = [1,2,4,4,8]
x = 4

print(bisect_left(a,x)) # 2
print(bisect_right(a,x)) # 4

 

[값이 특점 범위에 있는 데이터 개수 구하기]

from bisect import bisect_left, bisect_right

def count_by_range(a, left_value, right_value):
	right_index = bisect_right(a, right_value)
	left_index = bisect_left(a, left_value)
	return right_index - left_index

a = [1,2,3,3,3,3,4,4,8,9]

# 값이 4인 데이터 개수 출력
print(count_by_range(a, 4, 4)) # 2

# 값이 [-1,3] 범위에 있는 데이터 개수 출력
print(count_by_range(a, -1, 3)) # 6

🍀 [파라메트릭 서치(Parametric Search)]

파라메트릭 서치란?

최적화된 문제를 결정 문제('예' 혹은 '아니오')로 바꾸어 해결하는 기법

    - 예) 특정한 조건을 만족하는 가장 알맞은 값을 빠르게 찾는 최적화 문제

이진 탐색을 이용하여 해결 가능!


출처

📚 이것이 취업을 위한 코딩 테스트다 with 파이썬

 

 

'Algorithm' 카테고리의 다른 글

다이나믹 프로그래밍(Dynamic Programming, DP, 동적계획법)  (0) 2022.02.18
최단 경로(Shortest Path) 알고리즘  (0) 2021.09.16
정렬 (Sorting)  (0) 2021.09.12
DFS/BFS  (0) 2021.09.11
그리디 알고리즘(Greedy, 탐욕법)  (0) 2021.09.10
Comments