Heap은 우리가 우선순위 큐를 구현할 떄 빈번히 사용됩니다. 우선순위 큐란, 우선순위가 높은 것 먼저 빠져 나가는 것을 말합니다.
Max Heap
max(min) tree란 parent의 key가 child의 키보다 작지 않은 것을 말합니다. 그리고 max(min) heap는 complete binary tree로써, max (min) tree인 것을 말합니다.
즉 max (min) tree에서 root의 값은 최댓값이거나 최솟값이 될 수 밖에 없습니다.
또한 이들은 complete binary tree이기 때문에 우리는 array representation으로도 heap을 나타낼 수 있습니다.
Insertion into a Max Heap
여기서 저희는 bubble up process라는 것을 정의해야 합니다. 이는 새로운 node의 시작점으로부터 위로 올라가면서 이 새로 추가될 노드의 새로운 자리를 찾아가는 과정입니다.
그 다음으로는 trickle down입니다. 이는 맨 위 즉 root값을 빼고 가장 마지막의 값을 위로 올려가면서 아래로 비교하며, 그 값이 삽입될 값을 찾아가는 과정입니다.
간단히 bubble up process와 trickle down process를 알아 보았으니, c언어 코드로 작성해 보도록 하겠습니다.
/heap.c
#include <stdio.h>
#include <stdlib.h>
#define MAX_ELEMENTS 200
#define MAX_ARR_SIZE 1000
#define HEAP_FULL(n) (n == MAX_ELEMENTS - 1)
#define HEAP_EMPTY(n) (!n)
typedef struct
{
int key;
} element;
element heap[MAX_ELEMENTS];
int n = 0;
void iterInorder(element heap[], int size)
{
int stack[MAX_ELEMENTS];
int top = -1;
int i = 1;
while (1)
{
while (size >= i)
{
top++;
stack[top] = i;
i = i * 2;
}
if (top == -1)
return;
i = stack[top];
top--;
printf("%d ", heap[i].key);
i = i * 2 + 1;
}
}
void push(element item, int *n)
{
int i;
// 만약에 HEAP이 꽉 찼다면 에러
if (HEAP_FULL(*n))
{
fprintf(stderr, "The heap is full. \n");
exit(EXIT_FAILURE);
}
i = ++(*n);
while ((i != 1) && (item.key > heap[i / 2].key))
{
heap[i] = heap[i / 2];
i /= 2;
}
heap[i] = item;
}
element pop(int *n)
{
int parent, child;
element item, temp;
if (HEAP_EMPTY(*n))
{
fprintf(stderr, "The heap is empty. \n");
exit(EXIT_FAILURE);
}
item = heap[1];
temp = heap[(*n)--];
parent = 1;
child = 2;
while (child <= *n)
{
if ((child < *n) && (heap[child].key < heap[child + 1].key))
child++;
if (temp.key >= heap[child].key)
break;
heap[parent] = heap[child];
parent = child;
child *= 2;
}
heap[parent] = temp;
return item;
}
void printLI(int n)
{
printf("Level Order: ");
for (int i = 1; i <= n; i++)
{
printf("%d ", heap[i].key);
}
putchar('\n');
printf("Inorder: ");
iterInorder(heap, n);
putchar('\n');
}
int main(void)
{
FILE *fp_read = fopen("input.txt", "r");
int value;
element newElement = {0};
int n = 0;
while (fscanf(fp_read, "%d", &value) != EOF)
{
newElement.key = value;
push(newElement, &n);
}
printLI(n);
pop(&n);
printLI(n);
pop(&n);
printLI(n);
return 0;
}
먼저 push가 되는 과정을 보도록 하겠습니다. heap이 full이라는 것의 정의부터 시작해야 합니다. heap이 꽉 차려면 0번부터 시작하는 인덱스의 값이 n - 1이 될 때가 heap이 꽉 찼다고 설정한 때입니다. 이러한 heap이 꽉찬 경우는 저희는 삽입하지 못합니다.
위 그림을 참고하면 될 것 같습니다.
또 이러한 array representation된 배열들은 순회하는 방법이 정해져 있습니다. 먼저 배열을 순서대로 출력하면 Level order가 됩니다. 이를 구현하는 방법은 그냥 배열을 끝까지 (1 ~ n) 순회하면서 돌면 됩니다. 그리고 iterInorder라는 것이 있는데 반복해서 배열에서 중위 순회를 하는 방법을 말합니다. 여기에서는 stack을 사용하는데, 코드를 보시면 이해가 빠르게 되실 겁니다.
'School > DataStructure' 카테고리의 다른 글
Data Structure - Tree ( Selection Tree ) (0) | 2022.05.31 |
---|---|
Data Structure - Tree ( BST ) (0) | 2022.05.31 |
Data Structure - Hashing ( Dynamic Hashing ) (0) | 2022.05.30 |
Data Structure - Hashing ( Overflow handling ) (0) | 2022.05.30 |
Data Structure - Hashing ( Hash Functions ) (0) | 2022.05.29 |