[알고리즘] 힙 정렬

2022. 2. 10. 12:25·알고리즘/풀이 힌트
반응형

힙 정렬 : 힙 트리 구조 ( Heap Tree Structure)를 이용하는 정렬 방법

-> 병합 정렬 (Merge Sort) , 퀵 정렬 (Quick Sort) 만큼 빠른 정렬 알고리즘이다.

​

힙(Heap)이 무엇인지 알기 전에 이진 트리(Binary Tree)에 대해서 알아보자면

 

이진트리 : 컴퓨터 안에서 데이터를 표현할 때 데이터를 각 노드에 담은 뒤 노드를 두 개씩 이어 붙이는 구조 여기서 각 노드는 자식 노드가 2개 이하인 노드여야 합니다.

1 : Root(루트) 라고 하며 3, 4, 5 : Leaf(리프)하고 한다.

-> 이진트리의 종류도 많이 있는데 우선 완전 이진 트리를 알아보자면 데이터가 Root(루트) 노드 부터 시작해 자식 노드가 왼쪽 자식 노드, 오른쪽 자식 노드​​ 순으로 차근차근 들어가는 구조의 이진 트리입니다.

즉, 이진 트리의 노드가 중간이 비어있지 않고 빽뺵히 가득 찬 구조입니다.

 

힙 : 최솟값이나 최댓값을 빠르게 찾아내기 위해 완전 이진 트리를 기반으로 하는 트리 힙에는 최소 힙과 최대 힙이 존재하는데

​

최대 힙 : ' 부모 노드' 가 '자식 노드' 보다 큰 힙

   7 는 부모 노드 7이 자식 노드 4 5 보다 크기 때문에 최대 힙정렬이

4   5 성립된다. 하지만

​

  4 는 부모 노드 4가 자식노드인 6 보다 작기 때문에 최대 힙 정렬이

6  8 성립되지 않는다 .

​

위와 같이 최대 힙정렬이 성립되지 않을 때 힙정렬을 수행하기 위해서

힙 생성 알고리즘(Heapify Algorithm)을 사용한다.

힙 생성 알고리즘

- 특정한 노드의 두 자식 중에서 더 큰 자식과 자신의 위치를 바꾸는 알고리즘

- '하나의 노드' 를 대상으로 수행하며 '하나의 노드'를 제외하고 최대 힙 정렬이 구성되 있는 상태 라고 가정을 한다.

​

이때 힙 생성 알고리즘의 시간 복잡도는 하나의 자식 노드로 내려갈 때마다 노드의 갯수가 2배 씩 증가한다는 점

즉 자식 노드 2개당 1개의 부모 노드이기 때문에 O(logN)입니다.

​

-> 3개의 데이터가 있다면 힙 생성 알고리즘을 1번만 하게 되면 최대 힙 정렬이 되기 때문에 log2N입니다.

​

힙 정렬은 모든 원소를 힙 생성 알고리즘을 적용시켜 최대 힙 정렬을 시키기 때문에

힙 정렬의 시간 복잡도는 N(데이터 수) * log2N(힙 생성 알고리즘 시간 복잡도)

​

힙 정렬의 시간 복잡도

O(N * logN)

7 6 5 8 3 5 9 1 6 를 힙 정렬로 정렬 한다면

 

        7

     6    5      --> 제시된 수를 힙 정렬 모양으로 정렬한 뒤

  8  3  5  9

1  6

​

        7

     8    5      --> 6 이 최대 힙이 아니기 때문에 위치를 바꿔준다.

  6  3  5  9        8 3

1  6

​

        7

     8    9      --> 5 마찬가지로 최대 힙이 아니기 때문에 위치를 바꿔준다.

  6  3  5  5        5 9

1  6

​

        9

     8    7      --> 7 도 최대 힙이 아니기 때문에 바꿔주면 최대 힙 정렬이 완성된다.

  6  3  5  5        8 9

1  6

​

        6

     8    7      --> 그 후 최대 힙의 Root 값 9와 제일 마지막 Leaf 값 6의 위치를 바꿔준다.

  6  3  5  5

1  9

​

        8

     6    7      --> 제일 마지막 Leaf 값인 9를 제외하고 다시 최대 힙을 만들어 준다.

  6  3  5  5

1  9

​

        1

     6    7      --> 그 후 다시 최대 힙의 Root 값 8와 9를 제외한 제일 마지막 Leaf 값 1의 위치를 바꿔준다.

  6  3  5  5

8  9

​

        1

     3    5      --> 이 작업을 반복하여 정렬해 준다.

  5  6  6  7

8  9

​

이렇게 9개의 원소를 가진 힙을 최대힙으로 정렬하기 위해서 힙 생성 알고리즘을 하면 logN 즉 log 9 -> 4번만 연산하면 된다.

힙 정렬은 모든 원소에 힙 정렬을 적용시키기 때문에 N (데이터 수) * logN(힙 생성 알고리즘) 이 되는 것이다.

​

#include<stdio.h>

int num = 9;
int heap[9] = { 7, 6, 5, 8, 3, 5, 9, 1, 6 };
int count = 0;  // 연산 횟수 확인

int main(void) { //  7  6  5  8  3  5  9  1  6

//  최초 최대 힙 구성
	for (int i = 1; i < num; i++) {
		int c = i;
		do {
			int root = (c - 1) / 2;      //  c : 1 root : 0, 
			if (heap[root] < heap[c]) {  //  c : 2 root : 0, 
				int temp = heap[root];   //  c : 3 root : 1,
				heap[root] = heap[c];    //  c : 4 root : 1
				heap[c] = temp;
			} 
			count++;
			c = root;
		} while (c != 0);
	}

//	크기를 줄여가며 반복적으로 힙을 구성
	for (int i = num - 1; i >= 0; i--) {  // 1번 Leaf으로 이동하면 다신 그 위치값을 변경 할 필요가 없기 때문에 i--
		int temp = heap[0];   // 0번째( 즉 Root)을 Leaf로 이동
		heap[0] = heap[i];
		heap[i] = temp;

		int root = 0;
		int c;

		do {   // 다시 최대 힙 정렬
			c = 2 * root + 1;

			printf("%d %d \n", root, c);

		//	자식 중에 더 큰 값을 찾기
			if (c < i - 1 && heap[c] < heap[c + 1]) {   // c < i -1 를 하는 이유는
				c++;                                    // c++ 이 i가 될 경우 자리를 바꾼 최댓값이기 때문
			}

		//	Root 보다 자식이 더 크면 변경
			if (c < i && heap[root] < heap[c]) {  // 값의 변동은 더 큰 값 쪽에서만 변동이 일어나기 때문에
				int temp = heap[root];            // 해당 값의 자식 노드들만 힙 생성 알고리즘을 사용해주면 된다.
				heap[root] = heap[c];    
				heap[c] = temp;
			}

			count++;
			root = c;
		} while (c < i);
	}

	for (int i = 0; i < num; i++) {
		printf("%d ", heap[i]);
	}
}

 

위 예제에서도 연산을 할 때마다 count 변수에 값을 +1해주었는데 결과로 count의 값은 36

즉 9 * log​9 -> 9 * 4 = 36이 되었다.

​

힙 정렬은 병합 정렬과는 다르게 별도의 추가적인 배열이 필요하지 않다는 점에서 메모리 측면에서 몹시 효율적이다.

또 항상 O(N * log N)을 보장할 수 있다는 점에서도 몹시 강력한 정렬 알고리즘입니다.

이론적으로는 퀵 정렬, 병합 정렬보다 우위에 있다고 할 수 있지만 단순 속도만 비교하면 퀵 정렬이 평균적으로

더욱 빠르기 때문에 힙 정렬은 일반적으로는 많이 사용되지 않습니다.

 

반응형
저작자표시 비영리 변경금지

'알고리즘 > 풀이 힌트' 카테고리의 다른 글

[알고리즘] Stack ( 스택 )  (3) 2022.02.11
[알고리즘] 계수 정렬  (0) 2022.02.10
[알고리즘] C++ STL sort() 함수_Vector/Pair  (2) 2022.02.10
[알고리즘] C++ STL sort() 함수_class  (0) 2022.02.10
[알고리즘] 퀵 정렬_구현  (0) 2022.02.09
'알고리즘/풀이 힌트' 카테고리의 다른 글
  • [알고리즘] Stack ( 스택 )
  • [알고리즘] 계수 정렬
  • [알고리즘] C++ STL sort() 함수_Vector/Pair
  • [알고리즘] C++ STL sort() 함수_class
잉여개발자
잉여개발자
풀스택 개발자를 목표로 잉여롭게 개발 공부도 하면서 다양한 취미 생활도 즐기고 있는 잉여 개발자입니다.
  • 잉여개발자
    잉여로운 개발일지
    잉여개발자
    • 분류 전체보기 (789)
      • 개발정보 (36)
      • 개발환경 (7)
      • 개발생활 (19)
      • React (141)
        • 이론 (23)
        • 기능 (12)
        • 실험실 (88)
        • 버그 (6)
        • 패스트캠퍼스 (9)
        • Npm (3)
      • React Native (28)
        • 공통 (6)
        • TypeScript (3)
        • JavaScript (18)
        • 버그 (1)
      • Next.js (30)
        • 이론 (13)
        • 실험실 (13)
        • 버그 (3)
      • Web (35)
      • 알고리즘 (202)
        • 풀이 힌트 (39)
      • JavaScript (47)
      • TypeScript (29)
        • 기초 (27)
        • 실험실 (2)
      • Node.js (13)
        • 이론 (0)
        • 기능 (3)
        • 실험실 (9)
        • 버그 (1)
      • 도커 (4)
      • CCNA (22)
        • 이론 (4)
        • 문제 (18)
      • 취미생활 (167)
        • 잉여로운 칵테일 (2)
        • 잉여의 식물키우기 (130)
        • 잉여로운 여행기 (11)
        • 잉여의 제2외국어 (21)
        • 잉여로운 책장 (2)
      • Java (1)
        • Java의 정석 (1)
      • 꿀팁 공유 (3)
  • 태그

    리얼학습일기
    네트워크
    webpack
    javascript
    ChatGPT
    Babel
    다이소
    바질
    next.js
    영어독학
    CSS
    CCNA
    ReactNative
    덤프
    자바스크립트
    타일러영어
    타입스크립트
    Node.js
    알고리즘
    식물
    typescript
    리얼클래스
    Docker
    영어회화
    네이버 부스트캠프
    바질 키우기
    리액트
    redux
    프로그래머스
    react
  • hELLO· Designed By정상우.v4.10.1
잉여개발자
[알고리즘] 힙 정렬
상단으로

티스토리툴바