정렬되지 않은 리스트에서 heap을 이용하여 빠르게 중앙 값을 찾는 방법에 대해 알아보자.
힙(Heap) 자료구조와 파이썬으로 최대 힙 / 최소 힙을 구현하는 방법에 대한 설명은 우선순위 큐(Priority Queue)와 힙(Heap)게시글을 참고하면 된다.
[1, 2, 3]
의 배열에서는 2가 중앙값이다.[1, 2, 3, 4]
에서는 2와 3의 평균인 2.5가 중앙값이다.sorted()
를 사용하여 배열을 정렬할 수 있다.sorted()
함수를 사용하여 중앙값을 찾는 코드를 작성하면 다음과 같다.def find_median(arr):
n = len(arr)
sorted_arr = sorted(arr)
if n % 2 == 0:
# 짝수 개의 요소를 가지는 배열에서 중앙값은 가운데 두 요소의 평균
return (sorted_arr[n//2-1] + sorted_arr[n//2]) / 2
else:
# 홀수 개의 요소를 가지는 배열에서 중앙값은 가운데 요소
return sorted_arr[n//2]
sorted()
함수는 평균 시간 복잡도 O(nlogn)
으로 동작하므로 이 코드의 전체 시간 복잡도는 O(nlogn)
이다.O(logn)
의 시간 복잡도로 중앙값을 찾을 수 있다. O(nlogn)
의 시간 복잡도가 걸리므로, 입력값의 크기가 커질수록 중앙값을 찾는 데 걸리는 시간이 더 많아진다.Heap의 두 성질을 이용하여, 중앙값보다 작은 값들은 Max heap에, 중앙값보다 큰 값들은 Min heap에 저장하는 방식으로 중앙값을 찾는 알고리즘을 구현할 수 있다.
그림을 통해 자세히 이해해보자.
[9, 5, 4, 1, 8, 7, 6, 3, 2]
에서 중앙값을 찾으려고 한다.from heapq import heappop, heappush
max_heap = []
min_heap = []
# 규칙에 맞게 heap에 숫자 넣는 함수
def push_num(num):
# max_heap과 min_heap의 크기가 같다면 max_heap에 값을 넣는다.
if len(max_heap) == len(min_heap):
heappush(max_heap, -num)
# max_heap과 min_heap의 크기가 다르면 이전에 최대 힙에 넣은 것이기 때문에
# 개수를 맞춰주기 위해 최소 힙에 값을 넣는다.
else:
heappush(min_heap, num)
# 대소 조건 비교하기
# min_heap의 root 값이 max_heap의 root 값보다 작다면 두 수를 바꿔준다.
if min_heap and -max_heap[0] > min_heap[0]:
temp_min = heappop(min_heap)
temp_max = heappop(max_heap)
heappush(max_heap, -temp_min)
heappush(min_heap, -temp_max)
# 중앙 값 찾는 함수
def find_median():
if len(max_heap) == len(min_heap):
return (-max_heap[0] + min_heap[0]) / 2
else:
return -max_heap[0]
arr = [9, 5, 4, 1, 8, 7, 6, 3, 2]
for i in range(9):
push_num(arr[i])
print(find_median())
9
7.0
5
4.5
5
6.0
6
5.5
5
여기 맛집이네요