보관/자료구조-개념

히프의 구현

unhyepnhj 2024. 8. 25. 21:27

- 히프는 1차원 배열로 표현될 수 있음

- 히프의 각 요소들을 구조체 element로 정의하고, element의 1차원 배열을 만들어 히프 구현

#define MAX_ELEMENT 200

typedef struct {
	int key;
} element;
typedef struct {
	element heap[MAX_ELEMENT];
	int heap_size;	//현재 히프 안에 저장된 요소 개수
} HeapType;

 

- 히프를 생성하려면 아래와 같은 방법을 사용

HeapType heap;
HeapType* heap = create();	//동적 할당 이용

삽입 연산

- 히프에 새로운 요소가 들어오면, 일단 새로운 노드를 히프의 마지막 노드로 삽입

- 삽입 후에 새로운 노드를 부모 노드들과 교환하여 히프의 성질을 만족하도록 함

- 히프 크기를 1 증가

- 증가된 히프 크기 위치에 새로운 노드 삽입

- i가 루트 노드가 아니고 i번째 노드가 i의 부모 노드보다 크면

- i번째 노드와 부모 노드를 교환

//최대 히프에서
void insert_max_heap(HeapType* h, element item) {
	int i;
	i = ++(h->heap_size);

	//트리를 거슬러 올라가며 부모 노드와 비교
	while ((i != 1) && (item.key > h->heap[i / 2].key)) {	//루트 노드가 아니고 부모 노드보다 큰 값을 가졌을 때
		h->heap[i] = h->heap[i / 2];
		i /= 2;
	}
	h->heap[i] = item;	//새로운 노드 삽입
}

삭제 연산

- 최대 히프에서 삭제 연산은 루트 노드를 삭제하는 것

- 루트 노드 삭제 후 히프 재구성 필요(히프의 성질을 만족하기 위해 위, 아래 노드 교환)

- 루트 노드 반환을 위해 루트 노드를 item 변수에 저장

- 말단 노드를 루트 노드로 이동

- 히프 크기 1 감소

- 루트의 왼쪽 자식부터 비교

- i가 히프 트리 크기보다 작을 때(=히프 트리를 벗어나지 않으면) 아래 과정을 반복

- 오른쪽 자식이 더 크면 두 자식 노드 중 큰 값의 인덱스를 largest로 이동

- largest의 부모 노드가 largest보다 크면 중지

- 그렇지 않으면 largest와 largest의 부모 노드를 교환

- 한 레벨 아래로

- 최대값 반환

element delete_max_heap(HeapType* h) {
	int parent, child;
	element item, temp;

	item = h->heap[1];
	temp = h->heap[(h->heap_size)--];
	parent = 1;
	child = 2;

	while (child <= h->heap_size) {
		if((child < h->heap_size) && (h->heap[child].key) < h->heap[child + 1].key){
			child++;
		}
		if (temp.key >= h->heap[child].key) {
			break;
		}
		//한 단계 아래로
		h->heap[parent] = h->heap[child];
		parent = child;
		child *= 2;
	}
	h->heap[parent] = temp;
	return item;
}

히프 복잡도 분석

 

1. 삽입 연산

- 히프 트리를 타고 올라가며 부모 노드들과 교환

- 최악의 경우 루트 노드까지 올라가야 하므로 트리의 높이에 해당하는 비교 연산 또는 이동 연산이 필요

- 히프는 완전 이진 트리이므로 히프의 높이는 log₂n, 시간 복잡도는 O log₂n)

 

2. 삭제 연산

- 마지막 노드를 루트로 가져온 뒤 자식 노드들과 비교하여 교환

- 최악의 경우 최하위 레벨까지 내려가야 하므로 트리 높이만큼이 시간 소요

- 삭제의 시간 복잡도 또한 O(log₂n)


전체 프로그램

#include <stdio.h>
#include <stdlib.h>
#define MAX_ELEMENT 200

typedef struct {
	int key;
} element;
typedef struct {
	element heap[MAX_ELEMENT];
	int heap_size;
} HeapType;

//생성
HeapType* create() {
	return (HeapType*)malloc(sizeof(HeapType));
}
//초기화
void init(HeapType* h) {
	h->heap_size = 0;
}
//삽입
void insert_max_heap(HeapType* h, element item) {
	int i;
	i = ++(h->heap_size);

	//트리를 거슬러 올라가며 부모 노드와 비교
	while ((i != 1) && (item.key > h->heap[i / 2].key)) {
		h->heap[i] = h->heap[i / 2];
		i /= 2;
	}
	h->heap[i] = item;	//새로운 노드 삽입
}

//삭제
element delete_max_heap(HeapType* h) {
	int parent, child;
	element item, temp;

	item = h->heap[1];
	temp = h->heap[(h->heap_size)--];
	parent = 1;
	child = 2;

	while (child <= h->heap_size) {
		if((child < h->heap_size) && (h->heap[child].key) < h->heap[child + 1].key){
			child++;
		}
		if (temp.key >= h->heap[child].key) {
			break;
		}
		//한 단계 아래로
		h->heap[parent] = h->heap[child];
		parent = child;
		child *= 2;
	}
	h->heap[parent] = temp;
	return item;
}

int main(void) {
	element e1 = { 10 }, e2 = { 5 }, e3 = { 30 };
	element e4, e5, e6;
	HeapType* heap;

	heap = create();
	init(heap);

	//삽입
	insert_max_heap(heap, e1);
	insert_max_heap(heap, e2);
	insert_max_heap(heap, e3);

	//삭제
	e4 = delete_max_heap(heap);
	printf("< %d > ", e4.key);
	e5 = delete_max_heap(heap);
	printf("< %d > ", e5.key);
	e6 = delete_max_heap(heap);
	printf("< %d > ", e6.key);

	free(heap);
	return 0;
}

>>