일반 큐와는 다르게 들어온 순서와 상관없이 우선순위가 높은 데이터가 먼저 나오는 구조입니다.
우선순위 큐는 힙(Heap)이라는 자료구조를 활용해 구현 할 수 있으므로 힙을 먼저 알 수 구현할 수 있어야 합니다.
힙은 위와 같이 완전 이진 트리로 구성되며, 부모 노드는 최대 두개의 자식 노드를 가지고 있습니다.
부모 노드의 인덱스를 i라고 했을 때,
왼쪽 자식 노드는 2i+1, 오른쪽 자식 노드는 2i+2 의 인덱스를 가집니다.
heapq 모듈을 사용하여 최소 힙 구현
import heapq
test = [3, 2, 5, 1, 7, 8, 2]
heapq.heapify(test) # heapify(list) : list를 힙 정렬합니다.
print(test) # [1, 2, 2, 3, 7, 8, 5]
heapq.heappop(test) # 힙에서 가장 작은 요소(최소힙이므로 루트 노드)를 반환합니다.
print(test) # [2, 2, 5, 3, 7, 8]
heapq.heappush(test, 4) # 힙에 항목을 삽입합니다. > heappush(list, 값)
print(test) # [2, 2, 4, 3, 7, 8, 5]
heapq 모듈을 사용하여 최대 힙 구현
test = [3, 2, 5, 1, 7, 8, 2]
heap = []
for i in test: # heap에 (-값, 값) 튜플 형태로 삽입
heapq.heappush(heap, (-i, i))
# 최대 힙 출력
for h in heap:
print(h[1], end = " ") # 8 5 7 1 2 3 2
# heappop
heapq.heappop(heap)[1] # [1]인덱싱을 통해 값 접근
# 루트 노드인 8 반환
힙 정렬 리스트에 (-i, i) 형태로 삽입하게 되면 튜플의 첫번째 요소를 우선순위로 최소 힙 정렬을 구성합니다.
실제 값은 두번째 요소에 저장되있으므로 heapq.heappop(heap)[1] 하면 루트 노드가 반환되고
실제 값을 확인할 수 있습니다.
리스트를 이용한 최대힙 구현
class Heapify(obejct):
def __init__(self, data = None):
self.data = [] or data # data가 None이면 빈 리스트[]
# 힙 정렬은 절반의 노드만 heapify 수행하면 됩니다.
for i in range(len(data) // 2, -1, -1):
self.__max_heapify__(i) # __max_heapify__() : 최대힙으로 heapify 수행
def __repr__(self):
return repr(self.data)
def left_child(self, i):
return (2 * i) + 1 # 왼쪽 자식 노드 인덱스
def right_child(self, i):
return (2 * i) + 2 # 오른쪽 자식 노드 인덱스
def parent(self, i):
return (i - 1) // 2 # 자식노드는 2*i+1, 2*i+2 이므로 i의 인덱스 구해서 반환
def __max_heapify__(self, i):
largest = i # largest 임시 변수, 부모 노드의 인덱스
left = self.left_child(i)
right = self.right_child(i)
n = len(self.data)
# 만약 left가 리스트 범위 내이고, left가 존재하며 left의 값이 largest값 보다 큰 경우
if left < n and self.data[left] > self.data[largest] and left:
largest = left
# 오른쪽 자식도 존재할 수 있으므로 왼쪽 비교 후 항상 오른쪽도 비교해주어야 함
if right < n and self.data[right] > self.data[largest] and right:
largest = right
# 자식노드와 비교 후 largest값에 변경이 이루어졌을 경우
# (largest가 자식노드 인덱스로 변경되었을 경우) > 인덱스를 맞춰줬으니 인덱스로 값을 바꿔줄 차례
if i != largest:
self.data[i], self.data[largest] = self.data[largest], self.data[i]
self.__max_heapify__(largest) # largest기준으로 heapify 추가 수행
# 최대값 반환하기
def extract_max(self):
n = len(self.data)
max_element = self.data[0] # 루트 노드를 반환할 변수에 대입
self.data[0] = self.data[n-1] # 가장 마지막 노드를 루트노드 자리로 이동
self.data = self.data[:n-1] # 마지막 노드를 루트로 복사했으므로 리스트 슬라이싱
self.__max_heapify__(0) # 루트 노드부터 heapify 수행
return max_element
# 최대힙 리스트에 삽입
def insert(self, item):
self.data.append(item)
i = len(self.data) - 1
# i가 0(루트 인덱스)가 아니고 부모 노드보다 i노드의 값이 클때까지 반복
while i != 0 and item > self.data[self.parent(i)]:
self.data[i] = self.data[self.parent(i)] # i의 값이 부모 노드 값보다 크기때문에
# 부모 노드의 값을 i노드에 대입
i = self.parent(i) # 인덱스를 부모 인덱스로 저장(부모 노드로 올라가면서 검사 반복)
self.data[i] = item
# 확인
if __name__ == "__main__"
list1 = [3, 2, 5, 1, 7, 8, 2]
heap = Heapify(list1)
print(heap) # [8, 7, 5, 1, 2, 3, 2]
heap.extract_max() # 8 반환
print(heap) # [7, 2, 5, 1, 2, 3]
heap.insert(10)
print(heap) # [10, 2, 7, 1, 2, 3, 5]
heapq모듈을 사용해서 우선순위 큐 구현
import heapq
class PriorityQueue(object):
def __init__(self):
self.queue = []
self.index = 0
def push(self, priority, item): # 우선순위와 값 매개변수
heapq.heappush(self.queue, (-priority, self.index, item))
# (-우선순위, 인덱스, 값) 형태로 heappush를 하면 우선순위가 높을수록 앞에 배치됩니다.
self.index += 1
def pop(self):
return heapq.heappop(self.queue)[-1] # heappop을 수행한 후 [-1]인덱싱을 통해 값에 접근합니다.
def __repr__(self):
return repr(self.queue)
if __name__ == "__main__":
q = PriorityQueue()
q.push(20, "Low")
q.push(0, "Very Low")
q.push(50, "Middle")
q.push(100, "Very High")
1. push(70, "High")
print(q)
# 결과
# [(-100, 3, 'Very High'), (-70, 4, 'High'), (-20, 0, 'Low'), (0, 1, 'Very Low'), (-50, 2, 'Middle')]
q.pop() # (-100, 3, 'Very High') 반환
q.pop() # (-70, 4, 'High') 반환
q.pop() # (-50, 2, 'Middle')
print(q) # [(-20, 0, 'Low'), (0, 1, 'Very Low')]
이상으로 힙, 힙을 이용한 우선순위 큐를 공부해 보았습니다.
다음으로는 노드를 이용해서 연결리스트를 해볼게요!
[Python] 스택 활용한 문제(문자열 거꾸로 출력, 괄호의 갯수 판별, 10진수를 n진수로 변환) (0) | 2021.11.19 |
---|---|
[Python] 단일 연결 리스트 / 끝에서 k번째 찾기 / 연결 리스트 분할 (0) | 2021.11.19 |
[Python] 단일 연결 리스트(LinkedList) (0) | 2021.11.19 |
[Python] 큐(Queue) 구현 (0) | 2021.11.10 |
[Python] 스택(Stack) 구현 (0) | 2021.11.10 |