-
반응형
1. 정의
-최댓값과 최솟값을 빠르게 찾기 위해 만들어진 완전 이진트리(complete Binary Tree)
#완전 이진트리: 노드를 삽입할 때 최하단 왼쪽 노드부터 차례대로 삽입하는 트리
-종류에는 최대 힙과 최소 힙이 있음
2. 사용하는 이유
-최댓값과 최솟값을 빠르게 찾기 위해서
-최댓값 최솟값을 찾을 때
배열을 사용하면 -> 시간 복잡도 O(n)
힙을 사용하면 -> 시간 복잡도 O(logn)
3. 구조
-완전 이진 트리 형태
-각 노드의 값이 해당 노드의 자식 노드의 값보다 크거나 같다(최대 힙) -> 최댓값이 rootnode에 담김
-각 노드의 값이 해당 노드의 자식 노드의 값보다 작거나 같다(최소 힙) -> 최솟값이 rootnode에 담김
4. Pyhon 모듈
#기본적으로 최소 힙 기능으로 작동한다.
import heapq: 모듈 import
heappush(): heap에 원소추가
heappop(): heap에서 원소 삭제
heapify(): list를 heap으로 만들기
물론 그냥 있는 모듈을 사용하는 게 가장 편한 방법이지만 원리에 조금 더 가까이 접근하기 위해 빙빙 돌아가는 구현을 해봅시다!
5. Python linked list로 maxheap구현
#maxheap코드 짜보기 class Heap: def __init__(self,data): self.heap_array = list() #안 헷갈리려고 index 1부터 시작 self.heap_array.append(None) self.heap_array.append(data) #insert함수에서 바꿔줘야하는 작업 해야하는지 판별하는 함수 def move_up(self,inserted_idx): #root node일 때 if inserted_idx<=1: return False parent_idx = inserted_idx//2 if self.heap_array[inserted_idx]>self.heap_array[parent_idx]: return True else: return False #delete함수에서 바꿔줘야하는 작업 해야하는지 판별하는 함수 def move_down(self, pop_idx): left_child_pop_idx = pop_idx * 2 right_child_pop_idx = pop_idx * 2 + 1 #1. 왼쪽 자식 노드도 없을 때 if left_child_pop_idx>=len(self.heap_array): return False #2. 왼쪽 자식 노드는 있고 오른쪽 자식 노드는 없을 떄 elif right_child_pop_idx>=len(self.heap_array): if self.heap_array[pop_idx]<self.heap_array[left_child_pop_idx]: return True else: return False #3. 왼쪽 자식, 오른쪽 자식 둘 다 있을 때 else: if self.heap_array[left_child_pop_idx]>self.heap_array[right_child_pop_idx]: #자식 노드 중 왼쪽이 더 클 때 if self.heap_array[popped_idx]<self.heap_array[left_child_pop_idx]: return True else: return False else: if self.heap_array[popped_idx]<self.heap_array[right_child_pop_idx]: #자식 노드 중 오른쪽이 더 클 때 return True else: return False #새로운 노드 추가하는 함수 def insert(self,data): #Root node에 아무것도 없다면 if len(self.heap_array) == 0: self.heap_array.append(None) self.heap_array.append(data) return True self.heap_array.append(data) #일단 넣어주고 그 이후에 순서 바꿔야할 부분 고려 inserted_idx = len(self.heap_array)-1 while self.move_up(inserted_idx): parent_idx = inserted_idx//2 self.heap_array[inserted_idx],self.heap_array[parent_idx] = self.heap_array[parent_idx], self.heap_array[inserted_idx] inserted_idx = parent_idx return True #max heap에서 맨 위의 루트노드를 삭제하고 다시 구조를 짜는 코드 def pop(self): if len(self.heap_array) <= 1: return None #max 추출 -> 맨앞이랑 맨 뒤랑 바꿔줌 pop_data = self.heap_array[1] #추출된 max node가 pop_data #완전한 heap구조가 될 때까지 맨 앞과 맨 뒤를 swap self.heap_array[1] = self.heap_array[-1] del self.heap_array[-1] pop_idx = 1 while self.move_down(pop_idx): left_child_pop_idx = popped_idx * 2 right_child_pop_idx = popped_idx * 2 + 1 #왼쪽 자식노드는 있고, 오른쪽 자식노드 없을 때 if right_child_pop_idx >= len(self.heap_array): if self.heap_array[pop_idx] < self.heap_array[left_child_pop_idx]: self.heap_array[pop_idx], self.heap_array[left_child_pop_idx] = self.heap_array[left_child_pop_idx], self.heap_array[pop_idx] pop_idx = left_child_pop_idx #왼쪽, 오른쪽 모두 자식노드 있을 때 else: if self.heap_array[left_child_pop_idx] > self.heap_array[right_child_pop_idx]: if self.heap_array[pop_idx] < self.heap_array[left_child_pop_idx]: self.heap_array[pop_idx], self.heap_array[left_child_pop_idx] = self.heap_array[left_child_popped_idx], self.heap_array[popped_idx] pop_idx = left_child_pop_idx else: if self.heap_array[pop_idx] < self.heap_array[right_child_pop_idx]: self.heap_array[pop_idx], self.heap_array[right_child_pop_idx] = self.heap_array[right_child_popped_idx], self.heap_array[popped_idx] pop_idx = right_child_pop_idx return pop_data
[Insert 함수]
- 새로운 값을 추가하는 함수
- 일단 완전 이진트리처럼 새로운 값을 최하단 왼쪽에 삽입
- move_up함수를 통해 parent_node와 swap 해야 되는지 여부를 판별한 후, 구조가 안정화될 때까지 수정해줌
[pop 함수]
- 맨 위에 있는 max값을 추출한 후, 다시 구조를 짜는 함수
- root node가 사라지면 마지막 노드가 그 자리를 일단 채운다.
- 이후부터는 move_down함수를 통해 child_node와 swap 해야 되는지 여부를 판별한 후, 구조가 안정화될 때까지 수정해줌
반응형'IT > 자료구조 & 알고리즘' 카테고리의 다른 글
[알고리즘] 선택정렬(Selection Sort) (Python) (0) 2021.07.29 [알고리즘] 버블정렬(Bubble Sort) (Python) (0) 2021.07.29 [자료구조] 트리(Tree) (Python) (1) 2021.07.29 [자료구조] 해쉬 테이블(Hash table) (Python) (0) 2021.07.28 댓글