01. 최소 힙
01-1) heapq 라이브러리를 사용하지 않고 구현
class PriorityQueue:
def __init__(self) :
self.data = []
def push(self, value) :
self.data.append(value)
index = len(self.data) -1
while index != 1 :
# 마지막으로 삽입한 값이 루트노드가 되면 종료
if self.data[index//2] > self.data[index] :
temp = self.data[index]
self.data[index] = self.data[index//2]
self.data[index//2] = temp
index = index//2
else : #self.data[index//2] <= self.data[index]
break
def pop(self) :
'''
우선순위가 가장 높은 원소를 제거합니다.
'''
if len(self.data) == 1:
return
# 마지막 노드를 루트 노드 자리로 이동
self.data[1] = self.data[-1]
self.data.pop()
#원래있었던 루트노드 사라짐
#[1,2,3,4] -> [4,2,3]
index = 1
while True :
pri = -1 #왼쪽 오른쪽 판단 변수
# 1. 아무 자식도 없는 경우
if len(self.data) -1 < index * 2 :
break
# 2. 왼쪽 자식만 있는 경우
elif len(self.data) -1 < index *2 +1 :
pri = index * 2
# 3. 왼쪽, 오른쪽 모두 자식이 있는 경우
else :
if self.data[index*2] <self.data[index*2 +1] :
pri = index *2
else :
pri = index*2 +1
if self.data[index] > self.data[pri] :
temp = self.data[index]
self.data[index] = self.data[pri]
self.data[pri] = temp
index = pri
else :
break
def top(self) :
'''
우선순위가 가장 높은 원소를 반환합니다. 만약 우선순위 큐가 비어있다면 -1을 반환합니다.
'''
if len(self.data) == 1 :
return -1
else :
return self.data[1]
01-2) heapq 라이브러리 사용하여 구현
import heapq
class PriorityQueue:
def __init__(self) :
self.data = []
def push (self, value):
heapq.heappush(self.data, value)
def pop (self) :
if len(self.data) > 0 :
heapq.heappop(self.data)
def top(self) :
if len(self.data) == 0:
return -1
else :
return self.data[0]
02. 최대 힙
import heapq
class PriorityQueue:
'''
우선순위 큐를 힙으로 구현합니다
'''
def __init__(self) :
self.data = []
def push (self, value):
heapq.heappush(self.data, -value)
def pop (self) :
if len(self.data) > 0 :
heapq.heappop(self.data)
def top(self) :
if len(self.data) == 0:
return -1
else :
return -self.data[0]
03. 절댓값 힙
import heapq
class PriorityQueue:
'''
우선순위 큐를 힙으로 구현합니다
'''
def __init__(self) :
self.data = []
def push(self, value) :
'''
우선순위 큐에 value를 삽입합니다.
'''
heapq.heappush(self.data, (abs(value), value))
def pop(self) :
'''
우선순위가 가장 높은 원소를 제거합니다.
'''
if len(self.data) > 0 :
heapq.heappop(self.data)
def top(self) :
'''
우선순위가 가장 높은 원소를 반환합니다. 만약 우선순위 큐가 비어있다면 -1을 반환합니다.
'''
if len(self.data) == 0 :
return -1
else :
return self.data[0][1]
04. 힙정렬
import heapq
class PriorityQueue:
def __init__(self) :
self.data = []
def push (self, value):
heapq.heappush(self.data, value)
def pop (self) :
if len(self.data) > 0 :
heapq.heappop(self.data)
def top(self) :
if len(self.data) == 0:
return -1
else :
return self.data[0]
def heapSort(items) :
'''
items에 있는 원소를 heap sort하여 리스트로 반환하는 함수를 작성하세요.
단, 이전에 작성하였던 priorityQueue를 이용하세요.
'''
result = []
pq = PriorityQueue()
for item in items :
pq.push(item)
for i in range(len(items)) :
result.append(pq.top())
pq.pop()
return result
05. 예제
05-1) 힘의 최솟값
import heapq
def getMinForce(weights) :
'''
n개의 점토를 하나로 합치기 위해 필요한 힘의 합의 최솟값을 반환하는 함수를 작성하세요.
'''
pq = []
result = 0
#heapq.heappush()
for w in weights :
heapq.heappush(pq, w)
while len(pq) > 1:
x = heapq.heappop(pq)
y = heapq.heappop(pq)
temp = x+y
result += temp
heapq.heappush(pq, temp)
return result
05-2) 중간값 찾기
import heapq
def find_mid(nums) :
'''
n개의 정수들을 담고 있는 배열 nums가 매개변수로 주어집니다.
nums의 각 정수들이 차례대로 주어질 때, 매 순간마다
"지금까지 입력된 수 중에서 중간값"을 리스트로 저장하여 반환하세요.
'''
n = len(nums)
result = []
l = [] # 최대 힙
r = [] # 최소 힙
for i in range(n) :
x = nums[i]
if not l or not r : #l 또는 r이 비어있는 경우
heapq.heappush(l, -x)
else :
if x >= -l[0] :
heapq.heappush(r, x) #루트노드 비교
else :
heapq.heappush(l, -x)
# 두 힙 크기 조정
# l과 r이 갖고있는 자료의 개수는 같아야하며
#총 자료의 개수가 홀수면 l이 하나 더 많이 들고있게 해야함.
while not (len(l) == len(r) or len(l) == len(r)+1) :
#l이 들고있는 개수가 r의 개수보다 2개 이상이다.
if len(l) > len(r):
#l에서 값을 뽑아서 r에 넣는다.
heapq.heappush(r, -heapq.heappop(l))
# r이 l보다 많이 가진 경우
else :
# r에서 값을 뽑아서 l에 넣는다.
heapq.heappush(l, -heapq.heappop(r))
result.append(-l[0])
return result