// Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. using System; namespace Framework.Collections { /// /// The IndexMinPriorityQueue class represents an indexed priority queue of generic keys. /// /// IndexMinPQ class from Princeton University's Java Algorithms /// Type must implement IComparable interface public class IndexMinPriorityQueue where T : IComparable { private readonly T[] _keys; private readonly int _maxSize; private readonly int[] _pq; private readonly int[] _qp; /// /// Constructs an empty indexed priority queue with indices between 0 and the specified maxSize - 1 /// /// The maximum size of the indexed priority queue public IndexMinPriorityQueue(int maxSize) { _maxSize = maxSize; Size = 0; _keys = new T[_maxSize + 1]; _pq = new int[_maxSize + 1]; _qp = new int[_maxSize + 1]; for (int i = 0; i < _maxSize; i++) { _qp[i] = -1; } } /// /// The number of keys on this indexed priority queue /// public int Size { get; private set; } /// /// Is the indexed priority queue empty? /// /// True if the indexed priority queue is empty, false otherwise public bool IsEmpty() { return Size == 0; } /// /// Is the specified parameter i an index on the priority queue? /// /// An index to check for on the priority queue /// True if the specified parameter i is an index on the priority queue, false otherwise public bool Contains(int i) { return _qp[i] != -1; } /// /// Associates the specified key with the specified index /// /// The index to associate the key with /// The key to associate with the index public void Insert(int index, T key) { Size++; _qp[index] = Size; _pq[Size] = index; _keys[index] = key; Swim(Size); } /// /// Returns an index associated with a minimum key /// /// An index associated with a minimum key public int MinIndex() { return _pq[1]; } /// /// Returns a minimum key /// /// A minimum key public T MinKey() { return _keys[_pq[1]]; } /// /// Removes a minimum key and returns its associated index /// /// An index associated with a minimum key that was removed public int DeleteMin() { int min = _pq[1]; Exchange(1, Size--); Sink(1); _qp[min] = -1; _keys[_pq[Size + 1]] = default; _pq[Size + 1] = -1; return min; } /// /// Returns the key associated with the specified index /// /// The index of the key to return /// The key associated with the specified index public T KeyAt(int index) { return _keys[index]; } /// /// Change the key associated with the specified index to the specified value /// /// The index of the key to change /// Change the key associated with the specified index to this key public void ChangeKey(int index, T key) { _keys[index] = key; Swim(_qp[index]); Sink(_qp[index]); } /// /// Decrease the key associated with the specified index to the specified value /// /// The index of the key to decrease /// Decrease the key associated with the specified index to this key public void DecreaseKey(int index, T key) { _keys[index] = key; Swim(_qp[index]); } /// /// Increase the key associated with the specified index to the specified value /// /// The index of the key to increase /// Increase the key associated with the specified index to this key public void IncreaseKey(int index, T key) { _keys[index] = key; Sink(_qp[index]); } /// /// Remove the key associated with the specified index /// /// The index of the key to remove public void Delete(int index) { int i = _qp[index]; Exchange(i, Size--); Swim(i); Sink(i); _keys[index] = default; _qp[index] = -1; } private bool Greater(int i, int j) { return _keys[_pq[i]].CompareTo(_keys[_pq[j]]) > 0; } private void Exchange(int i, int j) { int swap = _pq[i]; _pq[i] = _pq[j]; _pq[j] = swap; _qp[_pq[i]] = i; _qp[_pq[j]] = j; } private void Swim(int k) { while (k > 1 && Greater(k / 2, k)) { Exchange(k, k / 2); k = k / 2; } } private void Sink(int k) { while (2 * k <= Size) { int j = 2 * k; if (j < Size && Greater(j, j + 1)) { j++; } if (!Greater(k, j)) { break; } Exchange(k, j); k = j; } } } }