노션으로 다시 돌아갔습니다 😅

힙 정렬 (Heap Sort) - Java (ing)

by mignon25

힙 정렬(Heap Sort)이란?

  • 시간 복잡도 : O(NlogN)
  • 병합 정렬(Merge Sort)과 퀵 정렬(Quick Sort)만큼 빠른 정렬 알고리즘
  • 힙 트리 구조(Heap Tree Structure)를 이용하는 정렬 방법
    => 힙 정렬을 하기 위해서는 정해진 데이터를 힙 구조를 가지도록 만들어야 한다. 
  • 힙 정렬의 아이디어 => "힙(Heap)을 이용해 데이터를 정렬하면 어떨까?"

 

Heap 이란?

  • 이진 트리 : 모든 노드의 자식 노드가 2개 이하인 트리
  • 완전 이진 트리 : 이진트리의 노드가 중간에 비어있지 않고 빽빽히 왼쪽부터 가득 찬 구조
  • 힙(Heap)
    • 최소값이나 최대값을 빠르게 찾아내기 위해 완전 이진트리를 기반으로 하는 트리
    • 힙에는 최대 힙과 최소 힙이 존재한다. 
    • 최대 힙 : '부모 노드' 가 '자식 노드' 보다 큰 구조

 

 

 

최대 힙 구조에서의 힙 정렬

  • 모든 부모 노드가 자식 노드보다 큰 값을 가져야 한다. 

  • 최초로 자식노드를 갖는 레벨 부터 시작
    • 루트 노드를 0번 인덱스라고 가정했을 때, 
    • 전체 노드의 수를 2로 나눈 수에 해당하는 인덱스부터 시작하면 된다. 
    • (위의 그림이라면 전체 노드의 수가 5개이므로 2로 나눈 2번 인덱스에 해당하는 노드(value = 3) 부터 시작 
  • 자식 노드 중 더 큰 값을 부모 노드와 비교
    • 자식노드의 값이 더 클 경우 부모노드와 자리를 바꾼다. 
      => 2번 인덱스의 노드는 자식이 없으므로 자동으로 힙구조 성립.
      => 1번 인덱스(2) 노드의 자식 노드 4, 5 중 큰 값인 5를 자신의 값과 비교, 자식 노드 값이 더 크므로 자리를 바꾼다. 

  • 자리가 바뀐 노드(2)를 또 그 자식 노드와 비교한다.
    => 현재는 더이상 자식이 없으므로 힙 성립
  • 루트 노드까지 비교 작업 반복 

  • 최대 힙 구조 완성
  • 최대 힙 구조에서 루트 노드는 가장 큰 값을 가지고 있다. 
  • 루트 노드와 말단 노드를 바꾼다. 
  • 다시 힙구조로 바꾸는 작업 반복

 

힙 정렬 구현 - 최대 힙 구조 (1.  힙 정렬 직접 구현) 

public class MaxHeapSort {
    public static int[] maxHeapSort(int[] arr) {
        sort(arr);
        return arr;
    }
    public static void sort(int[] arr) {
        System.out.println("최초 입력받은 배열");
        System.out.println(Arrays.toString(arr));

        heapify(arr, arr.length);

        for(int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            System.out.println("최대값을 맨 뒤와 바꾼 후 배열");
            System.out.println(Arrays.toString(arr));
            heapify(arr, i);
        }
    }

    // 힙구조 완성하기
    public static void heapify(int[] arr, int idx) {
        for(int i = 1; i < idx; i++) { // i = 1 부터인 이유 : 자식노드를 확인해야 하므로 루트노드 제외
            int child = i;
            while(child > 0) {
                int parent = (child - 1) / 2;
                if(arr[child] > arr[parent]) {
                    swap(arr, child, parent);
                }
                child = parent;
            }
        }
        System.out.println("최대 힙 구조로 변환한 배열");
        System.out.println(Arrays.toString(arr));
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr1 = {28, 132, 98, 30, 1, 4895, 52, 7, 123};
        int[] arr2 = {7,7,3,2,1,8,9,10,10,7};

        System.out.println(Arrays.toString(maxHeapSort(arr1)));
        System.out.println(Arrays.toString(maxHeapSort(arr2)));
    }
}

 

힙 정렬 구현 - 최소 힙 구조 (2. PriorityQueue 이용)

자바에는 PriorityQueuer 가 heap 구조를 자동으로 구현해주어, 정말 간단하게 힙정렬을 구현할 수도 있다. 

public class MinHeapSort {
    public static int[] minHeapSort(int[] arr){
        PriorityQueue<Integer> heap = new PriorityQueue<>();

        for(int i = 0; i < arr.length; i++) {
            heap.add(arr[i]);
        }

        for(int i = 0; i < arr.length; i++) {
            arr[i] = heap.poll();
        }

        return arr;
    }

    public static void main(String[] args) {
        int[] output = minHeapSort(new int[]{5, 4, 3, 2, 1});
        System.out.println(Arrays.toString(output)); // --> [1, 2, 3, 4, 5]

        output = minHeapSort(new int[]{3, 1, 21});
        System.out.println(Arrays.toString(output)); // --> [1, 3, 21]

        output = minHeapSort(new int[]{4, 10, 3, 5, 1});
        System.out.println(Arrays.toString(output)); // --> [1, 3, 4, 5, 10]
    }
}

 

 

 

 

 

 

'Algorithm' 카테고리의 다른 글

합병 정렬 (Merge Sort) - Java  (0) 2023.04.02
기수 정렬 (Radix Sort) - Java  (0) 2023.03.31
삽입 정렬 (Insert Sort) - Java  (0) 2023.03.31
퀵 정렬 (Quick Sort) - Java  (0) 2023.03.29
DFS - 전위 순회, 중위 순회, 후위 순회  (0) 2023.03.24

블로그의 정보

Mignon'S Dev Log

mignon25

활동하기