ν‹°μŠ€ν† λ¦¬ λ·°

λ°˜μ‘ν˜•

νž™(heap)도 이진 트리의 ν•œ μ’…λ₯˜λ‘œ 이진 νž™(binary heap) 이라고도 ν•œλ‹€. ν•˜μ§€λ§Œ μ΄μ§„νž™μ€ νŠΉλ³„ν•œ 쑰건듀을 λ§Œμ‘±ν•˜λŠ” 이진 νŠΈλ¦¬μ΄λ‹€.

  • λ£¨λ“œ(root) λ…Έλ“œκ°€ μ–Έμ œλ‚˜ μ΅œλŒ“κ°’ λ˜λŠ” μ΅œμ†Ÿκ°’μ„ 가진닀. μ΅œλŒ“κ°’μ„ 가지면 μ΅œλŒ€ νž™(max heap), μ΅œμ†Ÿκ°’μ„ 가지면 μ΅œμ†Œ νž™(min heap)이닀.
  • μ™„μ „ 이진 νŠΈλ¦¬μ—¬μ•Ό ν•œλ‹€.
  • μ΅œλŒ€ νž™ λ‚΄μ˜ μž„μ˜μ˜ λ…Έλ“œλ₯Ό 루트둜 ν•˜λŠ” μ„œλΈŒνŠΈλ¦¬ λ˜ν•œ μ΅œλŒ€νž™μ΄λ‹€. (μž¬κ·€μ μœΌλ‘œλ„ μ •μ˜κ°€ 됨)

μ΅œλŒ€νž™(Max Heap)의 예

 

 

 

 

이진 탐색 νŠΈλ¦¬μ™€μ˜ 비ꡐ

  1. μ›μ†Œλ“€μ€ μ™„μ „νžˆ 크기 순으둜 μ •λ ¬λ˜μ–΄μžˆλŠ”κ°€? 이진탐색은 κ·Έλ ‡μ§€λ§Œ νž™μ€ 그렇지 μ•Šλ‹€.
  2. νŠΉμ • ν‚€ 값을 κ°€μ§€λŠ” μ›μ†Œλ₯Ό λΉ λ₯΄κ²Œ 검색할 수 μžˆλŠ”κ°€? μ΄μ§„νƒμƒ‰νŠΈλ¦¬λŠ” κ°€λŠ₯, νž™μ€ λΆˆκ°€
  3. λΆ€κ°€μ˜ μ œμ•½ 쑰건은 μ–΄λ–€ 것인가? νž™μ€ μ΄μ§„νƒμƒ‰νŠΈλ¦¬μ— λΉ„ν•΄ μ™„μ „ μ΄μ§„νŠΈλ¦¬μ—¬μ•Όν•œλ‹€λŠ” μ œμ•½μ‘°κ±΄μ΄ μžˆλ‹€.

 

 

 

μ΅œλŒ€ νž™(Max Heap)의 좔상적 자료ꡬ쑰

μ—°μ‚°μ˜ μ •μ˜

  • __init__() - 빈 μ΅œλŒ€ νž™μ„ 생성
  • insert(item) - μƒˆλ‘œμš΄ μ›μ†Œλ₯Ό μ‚½μž…
  • remove() - μ΅œλŒ€ μ›μ†Œ(root node)λ₯Ό λ°˜ν™˜ν•˜κ³  μ‚­μ œ

 

 

 

 

데이터 ν‘œν˜„μ˜ 섀계

배열을 μ΄μš©ν•œ 이진 트리의 ν‘œν˜„

class MaxHeap:
    # 빈 νž™μ„ 생성
    def __init__(self):
        self.data = [None]

 

 

 

μ΅œλŒ€ νž™μ— μ›μ†Œ μ‚½μž…

트리의 λ§ˆμ§€λ§‰ μžλ¦¬μ— μƒˆλ‘œμš΄ μ›μ†Œλ₯Ό μž„μ‹œλ‘œ μ €μž₯

λΆ€λͺ¨ λ…Έλ“œμ™€ ν‚€ 값을 λΉ„κ΅ν•˜μ—¬ μœ„λ‘œ, μœ„λ‘œ 이동

트리의 λ§ˆμ§€λ§‰ μžλ¦¬μ— μƒˆλ‘œμš΄ μ›μ†Œλ₯Ό μž„μ‹œλ‘œ μ €μž₯
λΆ€λͺ¨ λ…Έλ“œμ™€ ν‚€ 값을 λΉ„κ΅ν•˜μ—¬ μœ„λ‘œ, μœ„λ‘œ 이동

 

 

class MaxHeap:
    def insert(self, item):
        # 흰트 - pythonμ—μ„œ 두 λ³€μˆ˜μ˜ κ°’ λ°”κΎΈκΈ°
        # a = 3, b = 5
        # a, b  = b, a
        self.data.append(item)
        
        index = len(self.data) -1
    
        while index != 1:
            numOfParentNode = index//2
            print(numOfParentNode)
            
            if self.data[numOfParentNode] < self.data[index]:
                self.data[numOfParentNode], self.data[index] = self.data[index], self.data[numOfParentNode]
                index = numOfParentNode
            else:
                break

 

 

 

 

 

μ΅œλŒ€ νž™μ— μ›μ†Œ μ‚½μž…μ˜ λ³΅μž‘λ„

μ›μ†Œμ˜ κ°œμˆ˜κ°€ n인 μ΅œλŒ€ νž™μ— μƒˆλ‘œμš΄ μ›μ†Œ μ‚½μž… -> λΆ€λͺ¨ λ…Έλ“œμ™€ λŒ€μ†Œ 비ꡐ μ΅œλŒ€ 회수 : log(2)N

μ΅œμ•… λ³΅μž‘λ„ O(logN)의 μ‚½μž… μ—°μ‚°

 

 

 

 

μ΅œλŒ€ νž™μ—μ„œ μ›μ†Œμ˜ μ‚­μ œ

루트 λ…Έλ“œμ˜ 제거 - 이것이 μ›μ†Œλ“€ 쀑 μ΅œλŒ“κ°’

트리 λ§ˆμ§€λ§‰ 자리 λ…Έλ“œλ₯Ό μž„μ‹œλ‘œ 루트 λ…Έλ“œμ˜ μžλ¦¬μ— 배치

μžμ‹ λ…Έλ“œλ“€κ³Όμ˜ κ°’ 비ꡐ와 μ•„λž˜λ‘œ, μ•„λž˜λ‘œ 이동 (μžμ‹μ€ λ‘˜μ΄ μžˆμ„ 수 μžˆλŠ”λ° 더 큰값을 κΈ°μ€€μœΌλ‘œ μ΄λ™ν•œλ‹€)

루트 λ…Έλ“œκ°€ μ΅œλŒ€κ°’μ΄λ―€λ‘œ 루트 λ…Έλ“œλ₯Ό μ œκ±°ν•œλ‹€.
트리의 λ§ˆμ§€λ§‰ 자리 λ…Έλ“œμΈ 4λ₯Ό μž„μ‹œλ‘œ 루트 λ…Έλ“œ μžλ¦¬μ— λ°°μΉ˜ν•œλ‹€.
μžμ‹ λ…Έλ“œλ“€κ³Όμ˜ κ°’ 비ꡐλ₯Ό 톡해 μ•„λž˜λ‘œ μ΄λ™ν•œλ‹€. 더 큰 ν‚€ 값을 κ°€μ§€λŠ” μžμ‹μͺ½μœΌλ‘œ 이동!

 

 

class MaxHeap:

    def remove(self):
        # ν•˜λ‚˜μ΄μƒμ˜ λ…Έλ“œκ°€ μ‘΄μž¬ν•˜λŠ” 경우
        if len(self.data) > 1:
            # λ§¨λ§ˆμ§€λ§‰ μ›μ†Œμ™€ μœ„μΉ˜λ°”κΎΈκΈ°
            self.data[1], self.data[-1] = self.data[-1], self.data[1]
            data = self.data.pop(-1)
            self.maxHeapify(1)
        else:
            data = None
        return data

    def maxHeapify(self, i):
        # iλŠ” μ–΄λŠ κΈ°μ€€μœΌλ‘œ 바꿀건가
        
        # μ™Όμͺ½ μžμ‹ (left child) 의 인덱슀λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
        left = i * 2
        # 였λ₯Έμͺ½ μžμ‹ (right child) 의 인덱슀λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
        right = i * 2 + 1
        greatest = i
        
        # μžμ‹ (i), μ™Όμͺ½μžμ‹(left), 였λ₯Έμͺ½μžμ‹(right) 쀑 μ΅œλŒ€λ₯Ό μ°Ύμ•„μ„œ μ΄κ²ƒμ˜ 인덱슀λ₯Ό smallest에 λ‹΄λŠ”λ‹€
        # μ™Όμͺ½ μžμ‹μ΄ μ‘΄μž¬ν•˜λŠ”μ§€, 그리고 μ™Όμͺ½ μžμ‹μ˜ (ν‚€) 값이 (무엇보닀?) 더 큰지λ₯Ό νŒλ‹¨ν•©λ‹ˆλ‹€.
        if left < len(self.data) and self.data[left] > self.data[greatest]:
            # 쑰건이 λ§Œμ‘±ν•˜λŠ” 경우, smallest λŠ” μ™Όμͺ½ μžμ‹μ˜ 인덱슀λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
            greatest = left

        # 였λ₯Έμͺ½ μžμ‹μ΄ μ‘΄μž¬ν•˜λŠ”μ§€, 그리고 였λ₯Έμͺ½ μžμ‹μ˜ (ν‚€) 값이 (무엇보닀?) 더 큰지λ₯Ό νŒλ‹¨ν•©λ‹ˆλ‹€.
        if right < len(self.data) and self.data[right] > self.data[greatest]:
            # 쑰건이 λ§Œμ‘±ν•˜λŠ” 경우, smallest λŠ” 였λ₯Έμͺ½ μžμ‹μ˜ 인덱슀λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
            greatest = right
            
        # λ§Œμ•½ 이 μΈλ±μŠ€κ°€ i와 같지 μ•Šλ‹€λ©΄ μžμ‹λ“€ 쀑에 λ‚˜λ³΄λ‹€ 큰 킀값을 가진 λ…Έλ“œκ°€ 발견된 경우
        if greatest != i:
            # ν˜„μž¬ λ…Έλ“œ (인덱슀 i) 와 μ΅œλŒ“κ°’ λ…Έλ“œ (μ™Όμͺ½ μ•„λ‹ˆλ©΄ 였λ₯Έμͺ½ μžμ‹) λ₯Ό κ΅μ²΄ν•©λ‹ˆλ‹€.
            self.data[i], self.data[greatest] = self.data[greatest], self.data[i]
            # μž¬κ·€μ  ν˜ΈμΆœμ„ μ΄μš©ν•˜μ—¬ μ΅œλŒ€ νž™μ˜ μ„±μ§ˆμ„ λ§Œμ‘±ν•  λ•ŒκΉŒμ§€ 트리λ₯Ό μ •λ¦¬ν•©λ‹ˆλ‹€.
            self.maxHeapify(greatest)

 

 

μ΅œλŒ€ νž™μœΌλ‘œλΆ€ν„° μ›μ†Œ μ‚­μ œ λ³΅μž‘λ„

μ›μ†Œμ˜ κ°œμˆ˜κ°€ n인 μ΅œλŒ€ νž™μ—μ„œ μ΅œλŒ€ μ›μ†Œ μ‚­μ œλŠ” μžμ‹ λ…Έλ“œλ“€κ³Όμ˜ λŒ€μ†Œ 비ꡐ μ΅œλŒ€ νšŒμˆ˜λŠ” 2 * log(2)N이닀.

μ΅œμ•… λ³΅μž‘λ„ O(logN)의 μ‚­μ œ μ—°μ‚°

 

 

 

 

 

μ΅œλŒ€/μ΅œμ†Œ νž™μ˜ μ‘μš©

1. μš°μ„  μˆœμœ„ 큐(priority queue)

  • enqueue ν•  λ•Œ "λŠμŠ¨ν•œ μ •λ ¬"을 이루고 μžˆλ„λ‘ 함 : O(logN)
  • dequeue ν•  λ•Œ μ΅œλŒ“κ°’μ„ μˆœμ„œλŒ€λ‘œ μΆ”μΆœ : O(logN)
  • 제 16κ°•μ—μ„œμ˜ μ–‘λ°©ν–₯ μ—°κ²° 리슀트 이용 κ΅¬ν˜„κ³Ό νš¨μœ¨μ„± 비ꡐ

 

2. νž™ μ •λ ¬ (heap sort)

  • μ •λ ¬λ˜μ§€ μ•Šμ€ μ›μ†Œλ“€μ„ 아무 μˆœμ„œλ‘œλ‚˜ μ΅œλŒ€ νž™μ— μ‚½μž… : O(logN)
  • μ‚½μž…μ΄ λλ‚˜λ©΄, νž™μ΄ λΉ„κ²Œ 될 λ•ŒκΉŒμ§€ ν•˜λ‚˜μ”© μ‚­μ œ : O(logN)
  • μ›μ†Œλ“€μ΄ μ‚­μ œλœ μˆœμ„œκ°€ μ›μ†Œλ“€μ˜ μ •λ ¬ μˆœμ„œ
  • μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜ λ³΅μž‘λ„ : O(logN)

 

def heapSort(unsorted):
    H = MaxHeap()
    for item in unsorted:
        H.insert(item)
    sorted = []
    d = H.remove()
    while d:
        sorted.append(d)
        d = H.remove()
    return sorted

 

 

 

 

 

전체 μ½”λ“œ

class MaxHeap:
    # 빈 νž™μ„ 생성
    def __init__(self):
        self.data = [None, 30, 24,12,18,21,8,6,4,2,19]
        
    def insert(self, item):
        # 흰트 - pythonμ—μ„œ 두 λ³€μˆ˜μ˜ κ°’ λ°”κΎΈκΈ°
        # a = 3, b = 5
        # a, b  = b, a
        self.data.append(item)
        
        index = len(self.data) -1
    
        while index != 1:
            numOfParentNode = index//2
            print(numOfParentNode)
            
            if self.data[numOfParentNode] < self.data[index]:
                self.data[numOfParentNode], self.data[index] = self.data[index], self.data[numOfParentNode]
                index = numOfParentNode
            else:
                break
                
                
    def remove(self):
        # ν•˜λ‚˜μ΄μƒμ˜ λ…Έλ“œκ°€ μ‘΄μž¬ν•˜λŠ” 경우
        if len(self.data) > 1:
            # λ§¨λ§ˆμ§€λ§‰ μ›μ†Œμ™€ μœ„μΉ˜λ°”κΎΈκΈ°
            self.data[1], self.data[-1] = self.data[-1], self.data[1]
            data = self.data.pop(-1)
            self.maxHeapify(1)
        else:
            data = None
        return data
    
    
    def maxHeapify(self, i):
        # iλŠ” μ–΄λŠ κΈ°μ€€μœΌλ‘œ 바꿀건가
        
        # μ™Όμͺ½ μžμ‹ (left child) 의 인덱슀λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
        left = i * 2
        # 였λ₯Έμͺ½ μžμ‹ (right child) 의 인덱슀λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
        right = i * 2 + 1
        greatest = i
        
        # μžμ‹ (i), μ™Όμͺ½μžμ‹(left), 였λ₯Έμͺ½μžμ‹(right) 쀑 μ΅œλŒ€λ₯Ό μ°Ύμ•„μ„œ μ΄κ²ƒμ˜ 인덱슀λ₯Ό smallest에 λ‹΄λŠ”λ‹€
        # μ™Όμͺ½ μžμ‹μ΄ μ‘΄μž¬ν•˜λŠ”μ§€, 그리고 μ™Όμͺ½ μžμ‹μ˜ (ν‚€) 값이 (무엇보닀?) 더 큰지λ₯Ό νŒλ‹¨ν•©λ‹ˆλ‹€.
        if left < len(self.data) and self.data[left] > self.data[greatest]:
            # 쑰건이 λ§Œμ‘±ν•˜λŠ” 경우, smallest λŠ” μ™Όμͺ½ μžμ‹μ˜ 인덱슀λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
            greatest = left

        # 였λ₯Έμͺ½ μžμ‹μ΄ μ‘΄μž¬ν•˜λŠ”μ§€, 그리고 였λ₯Έμͺ½ μžμ‹μ˜ (ν‚€) 값이 (무엇보닀?) 더 큰지λ₯Ό νŒλ‹¨ν•©λ‹ˆλ‹€.
        if right < len(self.data) and self.data[right] > self.data[greatest]:
            # 쑰건이 λ§Œμ‘±ν•˜λŠ” 경우, smallest λŠ” 였λ₯Έμͺ½ μžμ‹μ˜ 인덱슀λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
            greatest = right
            
        # λ§Œμ•½ 이 μΈλ±μŠ€κ°€ i와 같지 μ•Šλ‹€λ©΄ μžμ‹λ“€ 쀑에 λ‚˜λ³΄λ‹€ 큰 킀값을 가진 λ…Έλ“œκ°€ 발견된 경우
        if greatest != i:
            # ν˜„μž¬ λ…Έλ“œ (인덱슀 i) 와 μ΅œλŒ“κ°’ λ…Έλ“œ (μ™Όμͺ½ μ•„λ‹ˆλ©΄ 였λ₯Έμͺ½ μžμ‹) λ₯Ό κ΅μ²΄ν•©λ‹ˆλ‹€.
            self.data[i], self.data[greatest] = self.data[greatest], self.data[i]
            # μž¬κ·€μ  ν˜ΈμΆœμ„ μ΄μš©ν•˜μ—¬ μ΅œλŒ€ νž™μ˜ μ„±μ§ˆμ„ λ§Œμ‘±ν•  λ•ŒκΉŒμ§€ 트리λ₯Ό μ •λ¦¬ν•©λ‹ˆλ‹€.
            self.maxHeapify(greatest)
            
            
def heapSort(unsorted):
    H = MaxHeap()
    for item in unsorted:
        H.insert(item)
    sorted = []
    d = H.remove()
    while d:
        sorted.append(d)
        d = H.remove()
    return sorted
                
h = MaxHeap()
h.insert(50)


print(h.data)

h.remove()
print(h.data)
h.remove()
print(h.data)
λ°˜μ‘ν˜•
λŒ“κΈ€