ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 자료구조 Heap & Heap sort (힙 & 힙 정렬) + 구현
    알고리즘/개념 정리 2024. 2. 23. 18:00
    728x90

    Heap 자료구조 란?
    - 데이터에서 최댓값 과 최솟값을 빠르게 찾기 위해 고안된 완전 이진 트리
    시간 복잡도 : O(logN)

    이진 트리의 개념
    - node : 각각의 값을 노드라고 부름
    - root : 뿌리 노드, 레벨 0, 가장 최상단 노드로 부모 노드가 존재하지 않는 노드
    - parent node : 부모 노드, 아래에 자식 노드를 가지고 있는 노드
    - child node : 부모 노드로 뻗어나온 하위 노드
    • 완전 이진 트리의 일종으로, 왼쪽으로부터 자료구조를 채워나가는 형태
      • 오른쪽은 비어있는 경우가 있을 수 있음
      • 1차원 배열로 나타낼 수 있음 -> 정렬이 가능한 이유
        • 배열로 구현 시에, 인덱스 1로 시작하는 것으로 구현하면 편리함 (0으로 시작해도 무관)
    • 중복 값 허용

    <인덱스 1로 시작하는 경우>

    • (부모 노드의 인덱스) = (자식 노드 인덱스) / 2
    • (왼쪽 자식 노드의 인덱스) = (부모 노드의 인덱스) * 2
    • (오른쪽 자식 노드의 인덱스) = (부모 노드의 인덱스) * 2 + 1

    <인덱스 0 으로 시작하는 경우>

    • 부모 노드 인덱스 = (자식 노드 인덱스 - 1) / 2
    • 왼쪽 자식 노드 인덱스 = 부모 노드 인덱스 × 2 + 1
    • 오른쪽 자식 노드 인덱스 = 부모 노드 인덱스 × 2 + 2

    Heap 종류
    1. 최대(Max) 힙 : 부모 노드가 자식 노드 보다 큰 값을 갖는 경우
    2. 최소(Min) 힙 : 자식 노드가 부모 노드 보다 큰 값을 갖는 경우


    Heap Sort (힙 정렬)
    아래의 완전 이진 트리 형태를 최대 힙 구조로 만드는 정렬 방법을 통해 설명

    - 총 노드의 수 : 6 개
    - 가장 오른쪽 아래에 위치한 부모 노드 구하기 : (마지막 노드 인덱스) / 2 = 3

    1. 가장 오른쪽 아래에 위치한 부모 노드 - 자식 노드 간의 관계부터 최대 힙 구조를 이루는 지 확인

    2. 3번 노드의 자식 노드는 하나 뿐이므로 자식 노드와 비교하여 부모 노드가 작다면 자리를 바꿈
    -> 힙 구조를 이루게 됨

    3. 부모 노드와 동일한 선상의 좌측 부모 노드로 이동해서 힙 구조를 이루는지 확인

    4. 2번 노드의 자식 노드 중 더 큰 값을 찾아 부모 노드와 대조하여 자식 노드의 값이 크다면 자리를 바꿈
    -> 힙 구조를 이루게 됨

    5. 가장 좌측 부모 노드까지 확인을 했다면, 2번 노드와 3번 노드 즉, 부모 노드 역할을 했던 노드들의 부모 노드로 올라가 힙 구조를 이루는지 확인

    6. 자식 노드들의 값을 비교하여 큰 값을 부모 노드와 대조하여 자식 노드의 값이 크다면 자리를 바꿈
    -> 힙 구조를 이루게 됨

    7. 루트 노드까지 완료되었다면 다시 한 번, 처음 시작했던 최하위 부모노드로 돌아가 다시 한 번 확인
    -> 최대 힙 구조를 만족하도록 반복
    -> 단, 루트 노드는 처음 정렬을 수행하게 되면 최대 값을 가지게 되므로 루트 노드를 제외하고 반복
    -> 또한, 말단 노드의 경우는

    8. 최대 힙 구조를 만족하는지 반복하여 검사
    -> 만약 한 번이라도 swap(스왑, 자리 바꿈)이 발생했다면 다시 최대 힙 구조를 만족하는지 확인

    9. 스왑이 일어나지 않고 검사를 통해 최대 힙 구조가 만족이 되면 검사를 멈춤 = 최대 힙 정렬 완료
    -> 아래와 같이 최대 힙 정렬 구조로 정렬이 된 것을 확인


    Heap 의 추가 , 삭제

    *추후 보완 예정*


    JAVA 로 최대 힙 정렬 구현
    PriorityQueue(우선순위 큐) 를 사용하여 풀이가 가능

    PriorityQueue를 사용하면 힙 정렬 알고리즘 풀이가 가능하다.

    힙 정렬은 최소 힙 / 최대 힙 으로 정렬을 하는 방법이 있지만, 
    우선순위 큐의 경우에는 우선순위에 따라서 출력을 한다는 차이점이 존재한다.

    java.util.PriorityQueue 의 경우, 일반적인 Queue 와 사용법이 거의 유사

    import java.util.PriorityQueue;
    import java.util.Collections;
    
    class Main{
    	public void main(String[] args){
        	// 생성 - 제네릭에는 객체타입을 넣음
            PriorityQueue<Object> pq = new PriorityQueue<>();
            
            // 사용
            pq.size(); // 우선순위 큐 안에 들어있는 요소 수 확인
            pq.add(parameter);	// 우선순위 큐 안에 요소 제공
            pq.offer(parameter);	// 우선순위 큐 안에 요소 제공
            pq.peek();	// 우선 순위에 따른 가장 처음 반환 하는 요소를 꺼내지 않고 확인
            pq.poll(); // 우선 순위에 따른 가장 처음 반환 하는 요소를 꺼내어 확인 & 제거
            
            // PriorityQueue 의 경우 기본적으로 오름차순으로 정렬
            // 다른 순서로 정렬을 원할 경우
            
            // 1. Integer 의 경우 Collections 를 이용해 내림차순 정렬 가능
            PriorityQueue<Integer> pq2 = new PriorityQueue<>(Collections.reverseOrder());
            
            // 2. Comparator 이용하여 compare 메소드를 Override 해서 원하는 기준으로 정렬 가능
            PriorityQueue<int[]> pq3 = new PriorityQueue<>(new Comparator<int[]>(){
            	@Override
                public int compare(int[] o1, int[] o2){
                	// 정렬할 기준 입력
                	return
                }
            });
        }
    }
    728x90
Designed by planet-si