힙(Heap)
힙 클래스 구현하기
class Heap:
def __init__(self, data):
self.heap_array = list()
self.heap_array.append(None) # 0번째 인덱스에 None 삽입
self.heap_array.append(data) # 1번째 인덱스에 data 삽입
삽입 구현하기
def move_up(self, inserted_idx):
if inserted_idx <= 1: # 삽입한 데이터의 인덱스값이 1보다 같거나 작을 경우 = root node
return False
parent_idx = inserted_idx // 2 # 삽입한 데이터의 부모 인덱스값
if self.heap_array[inserted_idx] > self.heap_array[parent_idx]:
# 삽입한 데이터가 부모 데이터보다 값이 클 경우
return True
else:
return False
def insert(self, data):
if len(self.heap_array) == 0: # array에 삽입된 데이터가 없을 경우
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
삭제 구현하기
def move_down(self, poped_idx):
left_child_poped_idx = poped_idx * 2 # 삭제한 데이터의 왼쪽 자식노드
right_child_poped_idx = poped_idx * 2 + 1 # 삭제한 데이터의 오른쪽 자식노드
# 자식 노드가 없을 때
if left_child_poped_idx >= len(self.heap_array):
return False
# 왼쪽 자식 노드만 있을 때
elif right_child_poped_idx >= len(self.heap_array):
# 삭제할 노드보다 왼쪽 자식 노드가 더 클 경우
if self.heap_array[poped_idx] < self.heap_array[left_child_poped_idx]:
return True
else:
return False
# 왼쪽 오른쪽 자식 노드가 모두 있을 때
else:
# 왼쪽 자식노드가 오른쪽 자식노드보다 클 경우
if self.heap_array[left_child_poped_idx] > self.heap_array[right_child_poped_idx]:
# 삭제할 데이터가 왼쪽 자식노드보다 작을 경우
if self.heap_array[poped_idx] < self.heap_array[left_child_poped_idx]:
return True
else:
return False
else:
# 삭제할 데이터가 오른쪽 자식노드보다 작을 경우
if self.heap_array[poped_idx] < self.heap_array[right_child_poped_idx]:
return True
else:
return False
def pop(self):
if len(self.heap_array) <= 1: # 현재 리스트의 길이가 1보다 같거나 작을 경우 = 값이 없음
return None
returned_data = self.heap_array[1] # 리스트의 root node
self.heap_array[1] = self.heap_array[-1] # root node 자리에 마지막 데이터 삽입
del self.heap_array[-1] # 마지막 인덱스 삭제
poped_idx = 1 # 삭제한 데이터의 인덱스(root node의 idx)
while self.move_down(poped_idx):
left_child_poped_idx = poped_idx * 2
right_child_poped_idx = poped_idx * 2 + 1
# 왼쪽 자식 노드만 있을 경우
if right_child_poped_idx >= len(self.heap_array):
# 삭제할 데이터가 왼쪽자식노드보다 작을 경우
if self.heap_array[poped_idx] < self.heap_array[left_child_poped_idx]:
# 삭제할 데이터와 왼쪽자식노드 위치 변경
self.heap_array[poped_idx], self.heap_array[left_child_poped_idx] = self.heap_array[left_child_poped_idx], self.heap_array[poped_idx]
# 삭제한 데이터의 인덱스값을 왼쪽자식 인덱스값으로 변경
poped_idx = left_child_poped_idx
# 왼쪽 오른쪽 노드 모두 있을 경우
else:
# 왼쪽 자식노드가 오른쪽 자식노드보다 클 경우
if self.heap_array[left_child_poped_idx] > self.heap_array[right_child_poped_idx]:
# 삭제할 데이터가 왼쪽 자식노드보다 작을 경우
if self.heap_array[poped_idx] < self.heap_array[left_child_poped_idx]:
self.heap_array[poped_idx], self.heap_array[left_child_poped_idx] = self.heap_array[left_child_poped_idx], self.heap_array[poped_idx]
poped_idx = left_child_poped_idx
else:
# 삭제할 데이터가 오른쪽 자식노드보다 작을 경우
if self.heap_array[poped_idx] < self.heap_array[right_child_poped_idx]:
self.heap_array[poped_idx], self.heap_array[right_child_poped_idx] = self.heap_array[right_child_poped_idx], self.heap_array[poped_idx]
poped_idx = right_child_poped_idx
return returned_data
알고리즘 복잡도 계산이 필요한 이유
하나의 문제를 푸는 알고리즘은 다양함
다양한 알고리즘 중 어떤 알고리즘이 더 좋은지 분석하기 위해 복잡도를 정의하고 계산함
알고리즘 복잡도 계산 항목
알고리즘 성능 표기법
빅오 표기법
O(1)
def print_data(data):
print(data[0])
O(𝑙𝑜𝑔𝑛)
def print_data(data):
i = data
while i > 1:
print(i)
i = i / 2
O(n)
def print_data(data):
for i in range(len(data)):
print(data[i])
O(𝑛2)
def print_data(data):
for i in range(len(data)):
for j in range(len(data)):
print(data[i], data[j])
O(n)
def sum_all(n):
total = 0
for num in range(1, n+1):
total += num
return total
O(1)
def sum_all(n):
return int(n*(n+1)/2)
정렬(sort)
버블 정렬(bubble sort)
def bubblesort(data):
for i in range(len(data)):
for j in range(len(data) - i - 1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
return data
삽입 정렬(insertion sort)
[https://upload.wikimedia.org/wikipedia/commons/9/9c/Insertion-sort-example.gif]
def insertionsort(data):
for i in range(len(data)):
for j in range(i + 1, 0, -1):
if data[j] < data[j-1]:
data[j], data[j-1] = data[j-1], data[j]
else:
break
return data
선택 정렬(selection sort)
def selectionsrot(data):
for i in range(len(data)):
min = i
for j in range(i, len(data)-1):
if data[min] > data[j]:
min = j
data[min], data[i] = data[i], data[min]
return data