TIL 23.01.07

ν™©μ€ν•˜Β·2024λ…„ 1μ›” 7일
0

TIL

λͺ©λ‘ 보기
142/146

πŸ“ŒToday I Learned

νž™(Heap)

μ™„μ „μ΄μ§„νŠΈλ¦¬μ˜ 일쒅.
λΆ€λͺ¨ λ…Έλ“œμ™€ μžμ‹ λ…Έλ“œ 간에 νŠΉμ •ν•œ 쑰건을 λ§Œμ‘±ν•˜λŠ” 자료ꡬ쑰.

μ™„μ „ 이진 트리

λΆ€λͺ¨ λ…Έλ“œ 밑에 μžμ‹ λ…Έλ“œκ°€ μ΅œλŒ€ 2κ°œκΉŒμ§€ μžˆμ„ 수 있고, λ§ˆμ§€λ§‰ λ ˆλ²¨μ„ μ œμ™Έν•œ λͺ¨λ“  λ ˆλ²¨μ— λ…Έλ“œκ°€ μ™„μ „νžˆ μ±„μ›Œμ Έ μžˆλŠ” 트리 ꡬ쑰.

레벨

루트 λ…Έλ“œλΆ€ν„° μ‹œμž‘ν•˜μ—¬ 트리의 λͺ‡ 번째 측에 μžˆλŠ”μ§€ λ‚˜νƒ€λ‚Έλ‹€.
루트 λ…Έλ“œμ˜ 레벨 = 0

높이

리프 λ…Έλ“œλΆ€ν„° μ‹œμž‘ν•˜λ©°, 루트 λ…Έλ“œμ˜ λ†’μ΄λŠ” 트리의 전체 높이가 λœλ‹€.


νž™μ˜ μ’…λ₯˜

μ΅œλŒ€ νž™(Max Heap), μ΅œμ†Œ νž™(Min Heap)

μ΅œλŒ€ νž™(Max Heap)

λͺ¨λ“  λΆ€λͺ¨ λ…Έλ“œκ°€ κ·Έ μžμ‹ λ…Έλ“œλ³΄λ‹€ ν¬κ±°λ‚˜ 같은 값을 가진닀.
루트 λ…Έλ“œλŠ” 전체 νž™ μ€‘μ—μ„œ κ°€μž₯ 큰 값을 가진닀.

μ΅œμ†Œ νž™(Min Heap)

λͺ¨λ“  λΆ€λͺ¨ λ…Έλ“œκ°€ κ·Έ μžμ‹ λ…Έλ“œλ³΄λ‹€ μž‘κ±°λ‚˜ 같은 값을 가진닀.
루트 λ…Έλ“œλŠ” 전체 νž™ μ€‘μ—μ„œ κ°€μž₯ μž‘μ€ 값을 가진닀.


νž™ κ΅¬ν˜„ 방법

λ°°μ—΄(Array)

루트 λ…Έλ“œκ°€ λ°°μ—΄μ˜ 첫 번째 μΈλ±μŠ€μ— μœ„μΉ˜ν•œλ‹€.

μΈλ±μŠ€κ°€ 1λΆ€ν„° μ‹œμž‘ν•˜λŠ” 경우,
i μΈλ±μŠ€μ— μžˆλŠ” λ…Έλ“œμ˜ μ™Όμͺ½ μžμ‹ λ…Έλ“œ: 2 * i μΈλ±μŠ€μ— μœ„μΉ˜
i μΈλ±μŠ€μ— μžˆλŠ” λ…Έλ“œμ˜ 였λ₯Έμͺ½ μžμ‹ λ…Έλ“œ: 2 * i + 1 μΈλ±μŠ€μ— μœ„μΉ˜

νž™ κ΅¬ν˜„ μ½”λ“œ μ˜ˆμ‹œ

package datastructure;

public class MinHeap {
	public int[] heap;
	public int size;

	// νž™ ꡬ좕 (min heap)
	public void buildMinHeap(int[] arr) {
		this.size = arr.length;
		this.heap = new int[size + 1]; // heap[0]은 λ―Έμ‚¬μš©
		System.arraycopy(arr, 0, heap, 1, size); // heap[1]이 root

		// λΆ€λͺ¨ λ…Έλ“œλ“€μ„ μ—­μœΌλ‘œ 순회
		// νž™μ˜ κ°€μž₯ λ§ˆμ§€λ§‰μ— μœ„μΉ˜ν•œ λΆ€λͺ¨ λ…Έλ“œμ˜ 인덱슀 = 전체 νž™ μ‚¬μ΄μ¦ˆ / 2
		for (int i = size / 2; i >= 1; i--) {
			minHeapify(i);
		}
	}
	
	// heapify()
	// μ΅œμ†Œ νž™μ—μ„œ λΆ€λͺ¨ λ…Έλ“œκ°€ μžμ‹ λ…Έλ“œλ³΄λ‹€ 큰 경우 μœ„μΉ˜λ₯Ό λ°”κΎΌλ‹€.
	// μž¬κ·€μ μœΌλ‘œ μ§„ν–‰ν•˜μ—¬ 전체 νž™μ΄ μ΅œμ†Œ νž™μ˜ 쑰건을 λ§Œμ‘±ν•˜λ„λ‘ ν•œλ‹€.
	// μ΅œμ†Œ νž™μ˜ 쑰건: λͺ¨λ“  λΆ€λͺ¨ λ…Έλ“œλŠ” μžμ‹ λ…Έλ“œλ³΄λ‹€ μž‘κ±°λ‚˜ κ°™μ•„μ•Ό ν•œλ‹€.
	
	// νž™ ꡬ쑰둜 μž¬λ°°μ—΄
	public void minHeapify(int i) {
		int left = 2 * i;
		int right = 2 * i + 1;
		int smallest;
		
		//μ™Όμͺ½ μžμ‹ λ…Έλ“œμ™€ 비ꡐ
		if (left <= size && heap[left] < heap[i]) {
			smallest = left;
		} else {
			smallest = i;
		}
		
		//μœ„μ—μ„œ λΉ„κ΅ν•œ κ°’κ³Ό 였λ₯Έμͺ½ μžμ‹ λ…Έλ“œμ™€ 비ꡐ
		if (right <= size && heap[right] < heap[smallest]) {
			smallest = right;
		}
		
		// μžμ‹ λ…Έλ“œκ°€ 더 μž‘μœΌλ©΄ μœ„μΉ˜λ₯Ό λ°”κΎΈκ³ , minHeapify μž¬κ·€ 호좜
		if (smallest != i) {
			swap(i, smallest);
			minHeapify(smallest);	// μž¬κ·€ 호좜
		}
	}
	
	// 두 μš”μ†Œμ˜ μœ„μΉ˜λ₯Ό λ°”κΏˆ
	public void swap(int i, int j) {
		int temp = heap[i];
		heap[i] = heap[j];
		heap[j] = temp;
	}
	
	// νž™ λ°°μ—΄ 좜λ ₯
	public void printHeapArray() {
		for (int i = 1; i <= size; i++) {
			System.out.println(heap[i] + " ");
		}
		System.out.println();
	}
}

νž™ κ΅¬ν˜„μ½”λ“œ ν˜ΈμΆœν•˜κΈ°

package datastructure;

public class Clientmain {

	public static void main(String[] args) {

		int[] heapArray = {0, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7};
		MinHeap minHeap = new MinHeap();
		minHeap.buildMinHeap(heapArray);
		minHeap.printHeapArray();
	}

}

νž™ μ‹œκ°„ λ³΅μž‘λ„

O(log n)
heapify()κ°€ νž™μ˜ λ†’μ΄λ§ŒνΌ μž¬κ·€ν˜ΈμΆœμ„ ν•œλ‹€.

buildHeap() - O(n)

νž™μ˜ μ‚½μž…/μ‚­μ œ μ—°μ‚° - O(log n)
-> 트리의 μž¬μ •λ ¬ 진행

μ΅œλŒ€κ°’/μ΅œμ†Œκ°’ κ΅¬ν•˜λŠ”κ²½μš° - O(1)
-> νž™μ˜ 루트 κ°’ 쑰회


νž™ μ •λ ¬(Heap Sort)

νž™μ„ μ΄μš©ν•˜μ—¬ 배열을 μ •λ ¬ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜.
μ •λ ¬λ˜μ§€ μ•Šμ€ 배열을 μ΅œλŒ€ νž™μ΄λ‚˜ μ΅œμ†Œ μž…μœΌλ‘œ κ΅¬μ„±ν•˜κ³ , 루트 λ…Έλ“œλ₯Ό κ°€μž₯ λ§ˆμ§€λ§‰ λ…Έλ“œμ™€ κ΅ν™˜ν•œ ν›„ νž™ 크기λ₯Ό μ€„μ΄λŠ” 방식.

각 μ›μ†Œκ°€ k μœ„μΉ˜λ§ŒνΌ λ–¨μ–΄μ Έ μžˆλŠ” 배열인 k-sort 배열을 μ •λ ¬ν•  λ•Œ κ°€μž₯ 효율적인 방법이닀.

μž₯점

μ΅œμ•…, μ΅œμ„ μ˜ κ²½μš°μ—λ„ 평균 O(n log n)의 μ‹œκ°„ λ³΅μž‘λ„ λ³΄μž„.
λ³„λ„μ˜ λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 제자리 μ •λ ¬(in-place sorting) 방식 μ‚¬μš©.
-> μΌμ •ν•œ μ„±λŠ₯을 λ³΄μž„κ³Ό λ™μ‹œμ— λ³„λ„μ˜ λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

단점

μˆ«μžκ°€ 같은 κ²½μš°μ—λ„ μŠ€μ™‘μ΄ λ°œμƒν•˜μ—¬ μ•ˆμ •μ μ΄μ§€ μ•Šμ€ μ •λ ¬ 방법이닀.

κ΅¬ν˜„ μ˜ˆμ‹œ

package datastructure;

public class HeapSort {

	public void heapSort(int[] inputArray) {

		MinHeap minHeap = new MinHeap();

		// νž™ 생성
		minHeap.buildMinHeap(inputArray);

		// νž™ μ •λ ¬
		int j = 0;
		for (int i = minHeap.size; i >= 2; i++) {
			inputArray[j] = minHeap.heap[1]; // νž™μ˜ root(μ΅œμ†Œκ°’)을 배열에 μ €μž₯
			j++;
			minHeap.swap(1, i); // νž™μ˜ root와 λ§ˆμ§€λ§‰ μš”μ†Œλ₯Ό λ°”κΏˆ
			minHeap.size--; // νž™μ˜ 크기λ₯Ό μ€„μž„
			minHeap.minHeapify(1); // νž™μ„ μž¬λ°°μ—΄
		}

		// νž™μ˜ λ§ˆμ§€λ§‰ root값을 λ°°μ—΄ λ§ˆμ§€λ§‰μ— μ €μž₯
		inputArray[j] = minHeap.heap[1];
	}
}

μ‹œκ°„ λ³΅μž‘λ„

O(n log n)

νž™ 생성 - O(n)

νž™ μ •λ ¬μ—μ„œ νž™μ—μ„œ κ°€μž₯ 큰(λ˜λŠ” μž‘μ€) μ›μ†Œλ₯Ό μ œκ±°ν•˜κ³  νž™ μž¬μ •λ ¬ν•˜λŠ” 과정을 n번 반볡.
제거 μ—°μ‚° - O(log n)

-> O(n log n)

=> O(n) + O(n log n) = O(n log n)


좜처
https://yozm.wishket.com/magazine/detail/2312/

profile
μ°¨κ·Όμ°¨κ·Ό ν•˜λ‚˜μ”©

0개의 λŒ“κΈ€