자료구조/힙

최대 힙, 최소 힙 (배열로 구현)

둠치킨 2022. 2. 18. 22:34

힙 기본 설명

자료구조 중 최대 힙, 최소 힙이 있다. 힙은 완전 이진 트리의 구조를 갖고 있고 수의 집합에서 특정한 수를 꺼내올때 유용하다. 예를 들어 배열 {1, 2, 3, 4, 5}중에서 가장 작거나 큰 수를 꺼내올때 단순하게 생각하면 for loop을 이용하면 시간복잡도가 O(N)이 될테지만, 힙을 사용하면 시간복잡도를 O(logN)까지 줄일 수 있다.

 

연결리스트로 구현할 수도 있겠지만, 배열로 구현하는 것이 편하기 때문에 배열로 구현한다. 완전 이진 트리이기 때문에, 메모리 누수도 걱정할 필요 없다.

 

  • 최소 힙은 부모 노드가 자식 노드보다 항상 작거나 같은 구조다.
  • 최대 힙은 부모 노드가 자식 노드보다 항상 크거나 같은 구조다.

최소 힙 구현

백준 1927번을 기준으로 구현한 코드다.

#include <stdio.h>
#define MAX 100001

typedef struct min_heap 
{
    int arr[MAX];
    int size;
} min_heap;
 
void swap(int *a, int *b) 
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

void init_min_heap(min_heap *hp)
{
    hp->size = 0;
}

void insert(min_heap* hp,int data) 
{
    int here = ++hp->size;
     
    while ((here!=1)&&(data<hp->arr[here/2])) 
	{
        hp->arr[here] = hp->arr[here / 2];
        here /= 2;
    }
    hp->arr[here] = data;
}
 
int deleteData(min_heap *hp) 
{
    if (hp->size == 0)
		return 0;
    int ret = hp->arr[1];
    hp->arr[1]=hp->arr[hp->size--];
    int parent = 1;
    int child;
 
    while (1) 
	{
        child = parent * 2;
		
		//왼쪽, 오른쪽 자식이 있고 왼쪽 자식이 오른쪽 자식보다 클 때
        if (child + 1 <= hp->size && hp->arr[child]>hp->arr[child + 1])
            child++;
 	
		//자식이 없거나, 가장 작은 자식과 비교해서 부모가 더 작아지면 break.
        if (child>hp->size||hp->arr[child] > hp->arr[parent]) 
			break;
         
        swap(&hp->arr[parent], &hp->arr[child]);
        parent = child;
    }
     
    return ret;
}

int main(void) 
{
	min_heap hp;
	init_min_heap(&hp);
    int x, N;
	scanf("%d",&N);
    for (int i=0; i<N; i++)
	{
        scanf("%d",&x);
        if (x == 0)
			printf("%d\n",deleteData(&hp));
        else 
			insert(&hp, x);
    }
    
    return 0;
}

 

최대 힙 구현

백준 11279번을 기준으로 구현한 코드다.

#include <stdio.h>
#define MAX 100001

typedef struct max_heap 
{
    int arr[MAX];
    int size;
} max_heap;
 
void swap(int *a, int *b) 
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

void init_max_heap(max_heap *hp)
{
    hp->size = 0;
}

void insert(max_heap* hp,int data) 
{
    int here = ++hp->size;
     
    while ((here!=1)&&(data>hp->arr[here/2])) 
	{
        hp->arr[here] = hp->arr[here / 2];
        here /= 2;
    }
    hp->arr[here] = data;
}
 
int deleteData(max_heap *hp) 
{
    if (hp->size == 0)
		return 0;
    int ret = hp->arr[1];
    hp->arr[1]=hp->arr[hp->size--];
    int parent = 1;
    int child;
 
    while(1) 
	{
        child = parent * 2;
		
		//왼쪽, 오른쪽 자식이 있고 왼쪽 자식이 오른쪽 자식보다 클 때 부모를 오른쪽 자식과 바꿈
        if (child+1<=hp->size && hp->arr[child]<hp->arr[child + 1])
            child++;
 	
		//자식이 없거나, 가장 작은 자식과 비교해서 부모가 더 커지면 break
        if (child>hp->size||hp->arr[child] < hp->arr[parent]) 
			break;
         
        swap(&hp->arr[parent], &hp->arr[child]);
        parent = child;
    }
     
    return ret;
}

int main(void) 
{
	max_heap hp;
	init_max_heap(&hp);
    int x, N;
	scanf("%d",&N);
    for (int i=0; i<N; i++)
	{
        scanf("%d",&x);
        if (x == 0)
			printf("%d\n",deleteData(&hp));
        else 
			insert(&hp, x);
    }
    
    return 0;
}