[DS] 힙 (Heap) - Priority Queue ☑️

2022. 12. 21. 15:32·Data structure


힙의 조건

1. 완전 이진 트리
2. 힙 특성 : 모든 노드는 값을 갖고, 자식 노드(들) 값 보다 크거나 같다.
* 리스트가 A[0]부터 시작된다면, A[k]의 자식은 A[2*k+1]과 A[2*k+2], A[k]의 부모 노드는 A[(k-1)//2]이 된다.


스며 오르기 (percolateUp) : 원소 삽입
스며 내리기 (percolateDown) : 원소 삭제, 힙 생성



힙의 구현 (Python)

class Heap:
    def __init__(self, *args):
        if len(args) != 0:
            self.__A = args[0]  # 파라미터로 온 리스틓
        else:
            self.__A = []
    def percolateUp(self, i):
        parent = (i - 1) // 2
        if i > 0 and self.__A[i] > self.__A[parent]:
            self.__A[i], self.__A[parent] = self.__A[parent], self.__A[i]
            self.percolateUp(parent)
    def percolateDown(self, i):
        left = 2 * i + 1
        right = 2 * i + 2
        if left <= len(self.__A) - 1:
            child = left
            if right <= len(self.__A) - 1 and self.__A[right] > self.__A[left]:
                child = right
            if self.__A[i] < self.__A[child]:
                self.__A[i], self.__A[child] = self.__A[child], self.__A[i]
                self.percolateDown(child)
    def insert(self, x):
        self.__A.append(x)
        self.percolateUp(len(self.__A) - 1)
    def deleteMax(self):
        if self.isEmpy():
            return None  # max값을 리턴해 주어야 하므로, 값이 없는 경우의 예외를 처리해 주어야 함!
        self.__a[0], self.__a[-1] = self.__a[-1],self.__a[0]
        max = self.__a.pop()
        self.percolateDown(0)
        return max
    def buildHeap(self):
        for i in range((len(self.__A) - 2) // 2, -1, -1):
            self.percoltaeDown(i)
    def max(self):
        return self.__A[0]
    def isEmpty(self):
        return len(self.__A) == 0
    def clear(self):
        self.__A = []
    def size(self):
        return len(self.__A)



비재귀로 힙 구현하기(push, pop)

# 비재귀로 힙 구현하기

heap = [1,3,4,6,7,9]
def push(heap, x):
    heap.append(x)
    current = len(heap)-1
    # 현재 원소가 루트에 도달하면 종료한다.
    while current > 0:
        parent = (current-1)//2
        if heap[parent] > heap[current]:
            heap[parent], heap[current] = heap[current], heap[parent]
            current = parent
        else: break
push(heap, 2); print(heap)  # [1,3,2,6,7,9,4]
push(heap, 5); print(heap)  # [1,3,2,6,7,9,4,6]


heap = [1,3,2,6,7,9,4,6]
def pop(heap):
    if not heap: return None
    elif len(heap) == 1: return heap.pop()
    heap[0], heap[-1] = heap[-1], heap[0]
    retItem = heap.pop()
    current, child = 0, 1
    while child <= len(heap)-1:
        right = child + 1
        if right <= len(heap)-1 and heap[child] > heap[right]:
            child = right
        if heap[current] > heap[child]:
            heap[current], heap[child] = heap[child], heap[current]
            current = child
            child = current*2+1
        else: break
    return retItem
print(pop(heap))  # 1
print(pop(heap))  # 2
print(heap)  # [3,5,4,6,7,9]

 

 

// C언어로 구현한 힙(우선순위 큐)

#define parent(i) (i-1)//2
#define left(i) 2*i+1
#define right(i) 2*i+2
#include <stdio.h>
#include <stdlib.h>

typedef struct Heap{
    int capacity;
    int size;
    int* arr;
}Heap;

Heap* createHeap(int capacity){
    Heap* newHeap = (Heap*)malloc(sizeof(Heap));
    newHeap->capacity = capacity;
    newHeap->size = 0;
    newHeap->arr = (int*)malloc(sizeof(int)*capacity);
    return newHeap;
}

void exchange(int arr[],int i,int j){
    int temp;
    temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

// percolateDown
// Time complexity : O(log n)
void max_heapify(Heap* heap, int i){
    if(left(i) <= heap->size-1){
        int child = left(i);
        if(right(i) <= heap->size-1 && (heap->arr[child] < heap->arr[right(i)])){
            child = right(i);
        }
        if(heap->arr[i] < heap->arr[child]){
            exchange(heap->arr, i, child);
            max_heapify(heap, child);
        }
    }
}
void min_heapify(Heap* heap, int i){
    if(left(i) <= heap->size-1){
        int child = left(i);
        if(right(i) <= heap->size-1 && (heap->arr[child] > heap->arr[right(i)])){
            child = right(i);
        }
        if(heap->arr[i] > heap->arr[child]){
            exchange(heap->arr, i, child);
            max_heapify(heap, child);
        }
    }
}

// buildHeap
// Time complexity : O(n)
void build_max_heap(Heap* heap){
    for(int i = (heap->size-2)/2; i >= 0; i--)
        max_heapify(heap, i);
}
void build_min_heap(Heap* heap){
    for(int i = (heap->size-2)/2; i >= 0; i--)
        min_heapify(heap, i);
}

// percolateUp
void percolateUp(Heap* heap, int i, char* mod){
    if(mod == "max"){
        while(i>0 && heap->arr[parent(i)] < heap->arr[i]){
            exchange(heap->arr, i, parent(i));
            i = parent(i);
        }
    }
    else if(mod == "min"){
        while(i>0 && heap->arr[parent(i)] > heap->arr[i]){
            exchange(heap->arr, i, parent(i));
            i = parent(i);
        }
    }
}

// insertion
// Time complexity : O(log n)
void insert(Heap* heap, int key){
    if(heap->size == 0){
        heap->arr[0] = key;
        heap->size += 1;
    }
    else{
        heap->arr[++heap->size] = key;
        percolateUp(heap, heap->size, "max");
    }
}

// get
// Time complexity : O(1)
int get_max(Heap* heap){
    // max_heap일 때 유효함
    return heap->arr[0];
}


// extract
// Time complexity : O(log n)
int extract_max(Heap* heap){
    if(heap->size < 1) return 99;
    int max = heap->arr[0];
    heap->arr[0] = heap->arr[heap->size-1];
    max_heapify(heap, 0);
    return max;
}

int main(int argc, char* argv[]){
    Heap* heapq = createHeap(10);
    insert(heapq, 5);
    insert(heapq, 1);
    insert(heapq, 3);
    insert(heapq, 2);
    insert(heapq, 6);
    for(int i = 0; i < heapq->size; i++)
        printf("%d ", extract_max(heapq));
    
    return 0;
}

 

 

 

파이썬 heapq 모듈

heapq는 최소 힙(min-heap) 으로 구현, 항상 가장 작은 값이 루트에 위치

 

heapq.heapify(iterable)

 - 리스트를 힙 구조로 변환

 - O(n) 시간복잡도

 

heapq.heappush(heap, item)

 - 힙에 item을 추가

 - O(log n)

 

heapq.heappop(heap)

 - 가장 작은 원소(루트 노드) 를 제거하고 반환

 - O(log n)

 

 

import heapq

data = [3, 1, 5, 2, 4]
heapq.heapify(data)
print(data)  
# [1, 2, 5, 3, 4] - 내부적으로 최소 힙 구조를 가짐


heapq.heappush(data, 0)
print(data)  # [0, 1, 5, 3, 4, 2]


min_item = heapq.heappop(data)
print(min_item)  # 0
'Data structure' 카테고리의 다른 글
  • [DS] 정렬 (Sort)
  • [DS] 해시 테이블 (Hash Table)
  • [DS] 이진 검색 트리 (Binary Search Tree)
  • [DS] AVL 트리 (AVL Tree)
vysryoo
vysryoo
  • vysryoo
    vysryoo
    vysryoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (129)
      • Python (20)
      • Data structure (12)
      • Algorithm (14)
      • Operating system (18)
      • Programming language theory (12)
      • Computer architecture (6)
      • Softeware engineering (8)
      • Multicore (2)
      • Data Base (3)
      • Problem solving (24)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
vysryoo
[DS] 힙 (Heap) - Priority Queue ☑️
상단으로

티스토리툴바