1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
using System;
using System.Collections.Generic;
// 기본 값은 최소 우선순위 큐
public class PriorityQueue<T>
{
// 힙 조건 : 부모노드는 항상 자식노드보다 우선순위가 낮아야한다.
private readonly List<T> heap;
private readonly IComparer<T> comparer;
public PriorityQueue() : this(Comparer<T>.Default) { }
public PriorityQueue(IComparer<T> comparerValue)
{
heap = new List<T>();
comparer = comparerValue;
}
public int Count => heap.Count;
//맨 끝에 추가하고 힙 조건을 다시 체크
public void Enqueue(T item)
{
// 맨 끝에 추가
heap.Add(item);
int index = Count - 1;
// 힙 조건을 확인할 때까지 계속 돈다.
while (index > 0)
{
//방금 추가한 노드의 부모 노드
int parentIndex = (index - 1) / 2;
//부모 노드의 우선순위가 방금 추가한 노드보다 낮다면 힙조건이 만족한 것.
if (comparer.Compare(heap[index], heap[parentIndex]) >= 0)
break;
//부모 노드가 더 우선순위가 더 높다면 서로 바꾼다.
Swap(index, parentIndex);
//이제 바꾼 노드의 자식노드를 다시 검사한다.
index = parentIndex;
}
}
// 가장 낮은 우선순위를 가진 노드(맨 위에 있는 노드)을 반환하고 힙 조건을 다시 체크
public T Dequeue()
{
if (Count == 0)
{
Console.WriteLine("PriorityQueue's Count is 0!");
return default;
}
// 힙의 루트에 있는 항목이 가장 낮은 우선순위를 가진다.
// 최종 return되는 값은 이 값이지만, 힙 조건을 만족하는지 검사를 해야한다.
T item = heap[0];
// 힙의 마지막 노드를 맨 위로 이동시킨다.
heap[0] = heap[Count - 1];
heap.RemoveAt(Count - 1);
int index = 0;
// 힙 조건을 확인할 때까지 계속 돈다.
while (true)
{
int leftChildIndex = 2 * index + 1;
int rightChildIndex = 2 * index + 2;
// 모든 자식 노드를 확인한 경우 종료.
if (leftChildIndex >= Count)
break;
// 두 자식 노드 중 우선순위가 낮은 노드를 선택한다.
int minChildIndex = (rightChildIndex < Count //오른쪽 노드가 있는지 부터 검사.. 없다면 leftChildIndex를 반환한다.
&& comparer.Compare(heap[rightChildIndex], heap[leftChildIndex]) < 0) ? //둘 중 더 낮은 우선순위를 가진 노드를 뽑아야 한다.
rightChildIndex : leftChildIndex;
// 위 조건에서 뽑은 노드와 현재 노드를 비교한다.
// 뽑은 노드가 현재 노드보다 우선순위가 높다면, 힙 조건을 만족하는 것이니 안바꿔도 되고, 그만체크해도 된다.
if (comparer.Compare(heap[index], heap[minChildIndex]) <= 0)
break;
// 뽑은 노드가 현재 노드보다 우선순위가 낮다면, 현재 노드와 뽑은 노드를 바꿔줌으로서 힙 조건을 만족하게 한다.
Swap(index, minChildIndex);
// 이제 뽑았던 노드의 자식 노드를 다시 검사한다.
index = minChildIndex;
}
return item;
}
private void Swap(int indexA, int indexB)
{
T temp = heap[indexA];
heap[indexA] = heap[indexB];
heap[indexB] = temp;
}
}
|
cs |
'공부 > 알고리즘 및 기타 공부' 카테고리의 다른 글
이진탐색 (C#) 제네릭 (0) | 2023.04.24 |
---|---|
투 포인터 알고리즘 (C#) (0) | 2023.04.24 |
이진탐색 (C#) (0) | 2022.02.07 |
이진트리 구현 (C#) (0) | 2022.02.03 |
퀵 정렬 (C#) (0) | 2022.01.27 |