프로그래밍/자료구조
[자료구조] 힙(Heap)
znvlcm
2021. 6. 1. 16:12
힙구조
최댓값 혹은 최소값을 찾아내는 연산을 빠르게 하기 위해 고안된 완전이진트리를 기본으로 하는 자료구조
(루트가 최댓값 혹은 최소값이다.)
특징
루트가 최댓값을 나타내는 최대힙 - 부모값은 자식의 값보다 항상 크거나 같다..
루트가 최솟값을 나타내는 최소힙 - 부모값은 자식의 값보다 항상 작거나 같다.
형제간에는 대소관계가 정해지지않는다.
루트가 최대값 혹은 최소값을 가리킨다.
높이가 h인 이진트리
최대로 가질 수 있는 총 노드 수 = (2^h)-1
높이 h에서의 최대노드수 2^(h-1)
높이가 3일 때
1+2+4 = 7 (2^3)-1 =7
높이 3에서의 최대노드수 2^(3-1) = 4
자바코드 힙구현
import java.util.Arrays;
/**
* 최대힙구현클래스 최대힙 : 완전이진트리 구조의 자료구조, 부모노드가 자식노드보다 항상 같거나크다.
*
* @author "Amy"
*
*/
public class MyHeap {
private int[] heap;
private int length;
/**
* 생성자
*
* @param length 배열초기화를 위한 길이
*/
public MyHeap(int length) {
this.length = 0;
this.heap = new int[length];
}
/**
* 생성자
*
* @param array 입력배열
*/
public MyHeap(int[] array) {
this.heap = Arrays.copyOf(array, array.length);
this.length = array.length;
swapUpLeft(array.length - 1);
}
public int[] getHeapArray() {
return heap;
}
/**
* 힙에 자료 추가
*
* @param element 추가할 숫자
*/
public void add(int element) {
if (length > heap.length) {
System.out.println("정해진 힙의 크기를 초과하여 추가에 실패하였습니다.");
return;
}
heap[length] = element;
swapUp(length);
length++;
}
/**
* 데이터 추가시 부모노드가 자식노드보다 크도록 재구성 아래 노드부터 상위노드로 정렬진행
*
* @param node 체크할 말단 노드
*/
private void swapUp(int node) {
int parent = (int) Math.floor((node - 1) / 2.00);
int child = node;
while (parent >= 0) {
if (heap[parent] < heap[child]) {
swap(parent, child);
child = parent;
parent = (child - 1) / 2;
} else {
break;
}
}
}
/**
* 노드 삭제시, 윗노드부터 재구성하기위한 메서드
*
* @param node 상위 노드
*/
private void swapDown(int node) {
int parent = node;
int child1 = 2 * (parent + 1) - 1;
int child2 = 2 * (parent + 1);
if (child1 > length - 1) {
return;
}
int childMax = heap[child1] >= (child2 > length - 1 ? 0 : heap[child2]) ? child1 : child2;
if (heap[parent] < heap[childMax]) {
swap(parent, childMax);
swapDown(childMax);
}
return;
}
/**
* 입력배열을 힙으로 재구성하기 위한 메서드 아래/오른쪽부터 순차적 재구성
*
* @param node 마지막 노드
*/
private void swapUpLeft(int node) {
int parent = node;
int child1 = 0;
int child2 = 0;
while (parent >= 0) {
child1 = 2 * (parent + 1) - 1;
child2 = 2 * (parent + 1);
if (child1 > length - 1) {
parent--;
continue;
}
int childMax = heap[child1] >= (child2 > length - 1 ? 0 : heap[child2]) ? child1 : child2;
if (heap[parent] < heap[childMax]) {
swap(parent, childMax);
swapDown(childMax);
}
parent--;
}
}
/**
* 위치 바꿈 메서드
*
* @param i 위치바꿀 인덱스1
* @param j 위치바꿀 인덱스2
*/
private void swap(int i, int j) {
int tmp = heap[i];
heap[i] = heap[j];
heap[j] = tmp;
}
/**
* 최대값인 루트노드 삭제 메서드 루트노드 삭제 및 반환 재구성
*
* @return 삭제한 루트노드의 값
*/
public int deleteRoot() {
if (length == 0) {
System.out.println("힙에 데이터가 없습니디");
return -1;
}
int deleteElement = heap[0];
swap(0, length - 1);
heap[length - 1] = 0;
swapDown(0);
length--;
return deleteElement;
}
/**
* 힙의 출력을 위한 변환
*/
@Override
public String toString() {
return Arrays.toString(heap);
}
/**
* 힙을 트리구조로 출력
*/
public void printHeap() {
int h = 0;
int i = 0;
System.out.println("트리구조출력");
while (h <= (int) Math.ceil(Math.sqrt(length + 1))) {
for (int j = i; j < i + Math.pow(2, h); j++) {
if (j > length - 1) {
break;
}
System.out.print(heap[j] + "\t");
}
System.out.println();
i = i + (int) Math.pow(2, h);
h++;
}
}
}
테스트용코드
import java.util.Arrays;
public class MyHeapTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = new int[] {60,20,70,10,80,30,50,40};
int[] expected1 = new int[] {80,60,70,40,20,30,50,10};
int[] expected2= new int[] {80,70,60,40,20,30,50,10};
MyHeap h1 = new MyHeap(array);
System.out.printf("입력데이터 : %s \r\n 실제 힙: %s \r\n 예상힙 : %s \r\n",Arrays.toString(array), h1, Arrays.toString(expected1));
h1.printHeap();
MyHeap h2 = new MyHeap(8);
for(int i =0; i< array.length; i++) {
h2.add(array[i]);
}
System.out.printf("입력데이터 : %s \r\n 실제 힙: %s \r\n 예상힙 : %s \r\n",Arrays.toString(array), h2, Arrays.toString(expected2));
h2.printHeap();
h2.deleteRoot();
System.out.printf("최댓값 삭제후 힙 %s \r\n", h2);
h2.printHeap();
h2.deleteRoot();
System.out.printf("최댓값 삭제후 힙 %s \r\n", h2);
h2.printHeap();
}
}
출력결과
728x90