-
[JAVA] 자료구조 Heap & Heap sort (힙 & 힙 정렬) + 구현알고리즘/개념 정리 2024. 2. 23. 18:00728x90
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 = 31. 가장 오른쪽 아래에 위치한 부모 노드 - 자식 노드 간의 관계부터 최대 힙 구조를 이루는 지 확인
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 - 완전 이진 트리의 일종으로, 왼쪽으로부터 자료구조를 채워나가는 형태