using System; using System.Collections.Generic; /// /// Implementasi generic Priority Queue (Antrean Prioritas) menggunakan min-heap. /// Memungkinkan operasi enqueue, dequeue, dan update priority dengan efisien. /// /// Tipe elemen yang disimpan dalam antrean /// Tipe prioritas yang digunakan, harus implementasi IComparable public class PriorityQueue where TPriority : IComparable { // Menyimpan pasangan elemen dan prioritasnya dalam struktur heap private List> elements = new List>(); // Menyimpan indeks setiap elemen dalam heap untuk akses cepat private Dictionary elementIndexMap = new Dictionary(); /// /// Mendapatkan jumlah elemen dalam antrean prioritas /// public int Count => elements.Count; /// /// Menambahkan elemen baru ke dalam antrean prioritas dengan prioritas tertentu /// /// Elemen yang akan ditambahkan /// Prioritas dari elemen public void Enqueue(TElement element, TPriority priority) { elements.Add(Tuple.Create(element, priority)); elementIndexMap[element] = elements.Count - 1; HeapifyUp(elements.Count - 1); } /// /// Mengambil dan menghapus elemen dengan prioritas tertinggi (nilai terkecil) /// dari antrean prioritas /// /// Elemen dengan prioritas tertinggi /// Dilempar jika antrean kosong public TElement Dequeue() { if (elements.Count == 0) throw new InvalidOperationException("The priority queue is empty."); var element = elements[0].Item1; var last = elements[elements.Count - 1]; elements.RemoveAt(elements.Count - 1); if (elements.Count > 0) { // Pindahkan elemen terakhir ke root, lalu atur ulang heap elements[0] = last; elementIndexMap[last.Item1] = 0; HeapifyDown(0); } elementIndexMap.Remove(element); return element; } /// /// Memperbarui prioritas elemen yang sudah ada dalam antrean /// /// Elemen yang akan diperbarui prioritasnya /// Nilai prioritas baru /// Dilempar jika elemen tidak ditemukan public void UpdatePriority(TElement element, TPriority newPriority) { if (!elementIndexMap.ContainsKey(element)) throw new InvalidOperationException("Element not found in priority queue."); var index = elementIndexMap[element]; var oldPriority = elements[index].Item2; elements[index] = Tuple.Create(element, newPriority); // Jika prioritas baru lebih tinggi (nilai lebih kecil), heapify up if (newPriority.CompareTo(oldPriority) < 0) { HeapifyUp(index); } // Jika prioritas baru lebih rendah (nilai lebih besar), heapify down else { HeapifyDown(index); } } /// /// Mempertahankan properti heap dengan memindahkan elemen ke atas jika /// prioritasnya lebih tinggi dari parent /// /// Indeks elemen yang akan dipindahkan ke atas private void HeapifyUp(int index) { var parentIndex = (index - 1) / 2; if (index > 0 && elements[index].Item2.CompareTo(elements[parentIndex].Item2) < 0) { Swap(index, parentIndex); HeapifyUp(parentIndex); } } /// /// Mempertahankan properti heap dengan memindahkan elemen ke bawah jika /// prioritasnya lebih rendah dari child /// /// Indeks elemen yang akan dipindahkan ke bawah private void HeapifyDown(int index) { var leftChildIndex = 2 * index + 1; var rightChildIndex = 2 * index + 2; var smallest = index; // Cari child dengan prioritas tertinggi (nilai terkecil) if (leftChildIndex < elements.Count && elements[leftChildIndex].Item2.CompareTo(elements[smallest].Item2) < 0) { smallest = leftChildIndex; } if (rightChildIndex < elements.Count && elements[rightChildIndex].Item2.CompareTo(elements[smallest].Item2) < 0) { smallest = rightChildIndex; } // Jika child memiliki prioritas lebih tinggi, tukar dan lanjutkan heapify down if (smallest != index) { Swap(index, smallest); HeapifyDown(smallest); } } /// /// Menukar posisi dua elemen dalam heap dan memperbarui elementIndexMap /// /// Indeks elemen pertama /// Indeks elemen kedua private void Swap(int i, int j) { var temp = elements[i]; elements[i] = elements[j]; elements[j] = temp; // Perbarui elementIndexMap untuk mencerminkan posisi baru elementIndexMap[elements[i].Item1] = i; elementIndexMap[elements[j].Item1] = j; } }