카테고리 없음

힙 정렬(Heap Sort)

서원근양학계정 2023. 4. 23. 03:37

힙 정렬

힙 정렬(Heap Sort)은 완전 이진 트리인 힙을 이용해서 원소들의 최댓값이나 최솟값을 쉽게 찾고 그것을 이용해서 정렬하는 알고리즘입니다.

먼저 부모 노드의 값이 자식 노드의 값보다 큰 최대 힙 구조를 만들어줍니다.

그리고 가장 큰 값을 가지고 있는 루트 노드를 힙의 마지막 노드와 교환해 주고 다시 최대 힙 구조를 만들어줍니다. 이 과정을 원소의 수 - 1번 반복하면 정렬이 완료됩니다.

 

힙 정렬 예시

본격적인 힙 정렬을 하기 전에 부모 노드의 값이 자식 노드의 값보다 큰 최대 힙 구조를 만들어야 합니다.

힙은 1차원 배열을 이용해서 구현할 수 있습니다.

부모 노드와 자식 노드의 인덱스를 쉽게 구하기 위해서 배열의 0번째 공간은 사용하지 않고 1번째 공간부터 사용합니다.

부모 노드 인덱스 -> 자식 노드 인덱스 / 2

왼쪽 자식 노드 인덱스 -> 부모 노드 인덱스 * 2

왼쪽 자식 노드 인덱스 -> 부모 노드 인덱스 * 2 + 1

부모 노드의 값을 구하고 값이 자신의 값보다 작으면 둘을 교환합니다.

 

최대 힙이 완성되었다면 본격적인 힙 정렬을 시작합니다.

가장 큰 값을 가지고 있으면서 트리의 최상단에 위치한 루트 노드와 가장 마지막 노드를 교환합니다.

원래 부모 노드는 자식 노드보다 큰 값을 가지고 있어야 하는데 루트 노드와 가장 마지막 노드를 교환하면서 루트 노드는 자식 노드보다 큰 값을 가졌다고 할 수 없게 되었습니다.

따라서 루트 노드와 두 자식 노드 중 더 값이 큰 노드와 교환해줍니다.

이 과정을 교환된 노드에서 반복해줍니다.

위의 모든 과정을 원소의 개수 - 1번만큼 반복해줍니다.

 

힙 정렬 C++ 코드

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>

void BuildHeap(int number, int numbers[]);
void Heapify(int number, int numbers[], int index);
void HeapSort(int number, int numbers[]);
void Swap(int* a, int* b);

int main()
{
	int number;
	int numbers[1000];

	memset(numbers, 0, sizeof(numbers));

	scanf("%d", &number);

	for (int i = 1; i <= number; i++)
	{
		scanf("%d", &numbers[i]);
	}

	HeapSort(number, numbers);

	for (int i = 1; i <= number; i++)
	{
		printf("%d\n", numbers[i]);
	}
}

void HeapSort(int number, int numbers[])
{
	BuildHeap(number, numbers);

	for (int i = number; i > 1; i--)
	{
		Swap(&numbers[1], &numbers[i]);
		Heapify(i - 1, numbers, 1);
	}
}

void BuildHeap(int number, int numbers[])
{
	for (int i = 2; i <= number; i++)
	{
		while (i > 1)
		{
			int parent_node = i / 2;

			if (numbers[i] > numbers[parent_node])
			{
				Swap(&numbers[i], &numbers[parent_node]);
				i = parent_node;
			}
			else
				break;
		}
	}
}

void Heapify(int number, int numbers[], int index)
{
	if (index == 0)
		return;

	int current_node = index;
	int left_child_node = index * 2;
	int right_child_node = index * 2 + 1;

	if (left_child_node <= number && numbers[current_node] < numbers[left_child_node])
	{
		current_node = index * 2;
	}

	if (right_child_node <= number && numbers[current_node] < numbers[right_child_node])
	{
		current_node = index * 2 + 1;
	}

	if (current_node != index)
	{
		Swap(&numbers[index], &numbers[current_node]);
		Heapify(number, numbers, current_node);
	}
}

void Swap(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}

 

힙 정렬 시간복잡도

최선 평균 최악
nlog2n nlog2n nlog2n