- index(parent) = index(child) // 2
- index(left_child) = index(parent) * 2
- index(right_child) = index(parent) * 2 + 1
class Element:
def __init__(self, key):
self.key = key
class MaxHeap:
MAX_ELEMENT = 100
def __init__(self):
self.arr = [None for i in range(self.MAX_ELEMENT+1)]
self.heapsize = 0
def is_empty(self):
if self.heapsize == 0:
return True
return False
def is_full(self):
if self.heapsize >= self.MAX_ELEMENT:
return True
return False
def parent(self, idx):
return idx >> 1
def left(self, idx):
return idx << 1
def right(self, idx):
return (idx<<1) + 1
ex) 14, 2, 9 에 11 삽입
1) 완전 이진 트리 속성을 만족하기 위해 2의 왼쪽 서브트리로 11이 삽입됨 -> 최대 힙 특성 깨짐
2) 최대 힙 속성 만족을 위해 2와 11의 위치를 바꿈
def push(self, item):
if self.is_full():
raise IndexError("the heap is full")
self.heapsize += 1
cur_idx = self.heapsize
while cur_idx != 1 and item.key > self.arr[self.parent(cur_idx)].key:
self.arr[cur_idx] = self.arr[self.parent(cur_idx)]
cur_idx = self.parent(cur_idx)
self.arr[cur_idx] = item
self.heapsize += 1; cur_idx = self.heapsize;
: 완전 이진 트리를 유지하기 위해 마지막 원소의 다음 인덱스에 삽입while cur_idx != 1 and item.key > self.arr[self.parent(cur_idx)].key:
: cur_idx가 루트가 아니고 item의 키가 cur_idx 부모 키보다 큰 경우 실행pop 연산 : 최대값을 삭제함 = 즉, 루트 삭제
1) pop() 을 통해 최대값인 루트 노드 삭제 -> 최대 힙 특성 깨짐
2) heap의 마지막 요소를 루트 노드로 대체함 = temp 값
3) temp값의 자식 노드 중 키가 더 큰 값을 선택하여 바꿔주면 됨
def pop(self):
if self.is_empty():
return None
rem_elem = self.arr[1]
temp = self.arr[self.heapsize]
self.heapsize -= 1
cur_idx = 1
child = self.left(cur_idx)
while child <= self.heapsize:
if child < self.heapsize and self.arr[self.left(cur_idx)].key < self.arr[self.right(cur_idx)].key:
child = self.right(cur_idx)
if temp.key >= self.arr[child].key:
break
self.arr[cur_idx] = self.arr[child]
cur_idx = child
child = self.left(cur_idx)
self.arr[cur_idx] = temp
return rem_elem
temp = self.arr[self.heapsize]; self.heapsize -= 1
: 맨 마지막에 위치한 원소를 받아오면서 heapsize를 하나 줄임cur_idx = 1
: 루트에서 시작child = self.left(cur_idx)
: 루트 왼쪽 자식while child <= self.heapsize:
: child > self.heapsize면 arr[cur_idx]는 리프노드임.if child < self.heapsize and self.arr[self.left(cur_idx)].key < self.arr[self.right(cur_idx)].key : child = self.right(cur_idx)
: 오른쪽 자식이 있고, 오른쪽 자식의 키가 왼쪽 자식의 키보다 크면 child를 오른쪽 자식으로 이동if temp.key >= self.arr[child].key : break
: 최대 힙 특성 만족 시 breakself.arr[cur_idx] = self.arr[child]; cur_idx = child
: key가 큰 원소를 부모로 이동시킴.def print_heap(h):
for i in range(1, h.heapsize+1):
print("{}".format(h.arr[i].key), end=" ")
print()
if __name__ == "__main__":
h = MaxHeap()
h.push(Element(2))
h.push(Element(14))
h.push(Element(9))
h.push(Element(11))
h.push(Element(6))
h.push(Element(8))
print_heap(h)
while not h.is_empty():
rem = h.pop()
print(f"poped item is {rem.key}")
print_heap(h)
- 키를 가진 원소 집합을 위한 자료 구조
- 힙으로 구현
from heapq import heappop, heappush
class Element:
def __init__(self, key, string):
self.key= key
self.data = string
class MinPriorityQueue:
def __init__(self):
self.heap = []
def is_empty(self):
if not self.heap:
return True
return False
def push(self, item):
heappush(self.heap, (item.key, item.data))
def pop(self):
return heappop(self.heap)
def min(self):
return self.heap[0]
if __name__ == "__main__":
pq = MinPriorityQueue()
pq.push(Element(2, "kim"))
pq.push(Element(14, "park"))
pq.push(Element(9, "choi"))
pq.push(Element(11, "lee"))
pq.push(Element(6, "yang"))
pq.push(Element(8, "jang"))
while not pq.is_empty():
elem = pq.pop()
print(f"key[{elem[0]}] : data[{elem[1]}]")
heappush(self.heap, (item.key, item.data))
: key, data를 튜플로 묶어서 전달