/// <summary> /// Updates the degree of a cell, cascading to update the degree of the /// parents if necessary. /// </summary> /// <param name="cell">Cell to update.</param> private void UpdateCellsDegree( FibonacciHeapCell <TPriority, TValue> cell ) { Debug.Assert(cell != null); Debug.Assert(cell.Children != null); int oldDegree = cell.Degree; cell.Degree = cell.Children.First is null ? 1 : cell.Children.Max(x => x.Degree) + 1; if (oldDegree != cell.Degree) { if ( _degreeToCell.TryGetValue( oldDegree, out FibonacciHeapCell <TPriority, TValue> degreeMapValue ) && degreeMapValue == cell ) { _degreeToCell.Remove(oldDegree); } else if (cell.Parent != null) { UpdateCellsDegree(cell.Parent); } } }
private FibonacciHeapCell <TPriority, TValue> ReduceCell([NotNull] ref FibonacciHeapCell <TPriority, TValue> cell) { FibonacciHeapCell <TPriority, TValue> nextCell = cell.Next; while (_degreeToCell.TryGetValue(cell.Degree, out FibonacciHeapCell <TPriority, TValue> currentDegreeCell) && currentDegreeCell != cell) { _degreeToCell.Remove(cell.Degree); if (PriorityComparison(currentDegreeCell.Priority, cell.Priority) * _directionMultiplier <= 0) { if (cell == nextCell) { nextCell = cell.Next; } ReduceCells(currentDegreeCell, cell); cell = currentDegreeCell; } else { if (currentDegreeCell == nextCell) { nextCell = currentDegreeCell.Next; } ReduceCells(cell, currentDegreeCell); } } return(nextCell); }
/// <summary> /// Merges the given <paramref name="heap"/> into this heap. /// </summary> /// <param name="heap">Heap to merge.</param> /// <exception cref="Exception">If the heap is not in the same direction.</exception> public void Merge(FibonacciHeap <TPriority, TValue> heap) { if (heap is null) { throw new ArgumentNullException(nameof(heap)); } if (heap.Direction != Direction) { throw new InvalidOperationException("Heaps must go in the same direction when merging."); } if (heap.IsEmpty) { return; } bool isEmpty = IsEmpty; _cells.MergeLists(heap._cells); if ( isEmpty || PriorityComparison( heap.Top.Priority, Top.Priority ) * _directionMultiplier < 0 ) { Top = heap.Top; } Count += heap.Count; }
/// <summary> /// Removes the given <paramref name="cell"/> from this cells list. /// </summary> /// <param name="cell">Cell to remove.</param> internal void Remove( FibonacciHeapCell <TPriority, TValue> cell ) { Debug.Assert(cell != null); if (cell.Previous != null) { cell.Previous.Next = cell.Next; } else if (First == cell) { First = cell.Next; } if (cell.Next != null) { cell.Next.Previous = cell.Previous; } else if (_last == cell) { _last = cell.Previous; } cell.Next = null; cell.Previous = null; }
private void UpdateCellOppositeDirection([NotNull] FibonacciHeapCell <TPriority, TValue> cell, [NotNull] TPriority newKey) { cell.Priority = newKey; if (cell.Children != null) { List <FibonacciHeapCell <TPriority, TValue> > toUpdate = null; foreach (FibonacciHeapCell <TPriority, TValue> child in cell.Children) { if (PriorityComparison(cell.Priority, child.Priority) * _directionMultiplier > 0) { if (toUpdate is null) { toUpdate = new List <FibonacciHeapCell <TPriority, TValue> >(); } toUpdate.Add(child); } } if (toUpdate != null) { foreach (FibonacciHeapCell <TPriority, TValue> child in toUpdate) { cell.Marked = true; cell.Children.Remove(child); child.Parent = null; child.Marked = false; _cells.AddLast(child); UpdateCellsDegree(cell); } } } UpdateNext(); }
private void ChangeKeyInternal( FibonacciHeapCell <TPriority, TValue> cell, // Null authorized if deleting the cell TPriority newKey, bool deletingCell ) { Debug.Assert(cell != null); int delta = Math.Sign(PriorityComparison(cell.Priority, newKey)); if (delta == 0) { return; } if (delta == _directionMultiplier || deletingCell) { // New value is in the same direction as the heap UpdateCellSameDirection(cell, newKey, deletingCell); } else { // Not removing a cell so the newKey must not be null Debug.Assert(newKey != null); // New value is in opposite direction of Heap, cut all children violating heap condition UpdateCellOppositeDirection(cell, newKey); } }
/// <summary> /// Enqueues an element in the heap. /// </summary> /// <param name="priority">Value priority.</param> /// <param name="value">Value to add.</param> public FibonacciHeapCell <TPriority, TValue> Enqueue( TPriority priority, TValue value ) { if (priority == null) { throw new ArgumentNullException(nameof(priority)); } var newCell = new FibonacciHeapCell <TPriority, TValue> { Priority = priority, Value = value, Marked = false, Children = new FibonacciHeapLinkedList <TPriority, TValue>(), Degree = 1, Next = null, Previous = null, Parent = null, Removed = false }; // We don't do any book keeping or maintenance of the heap on Enqueue, // We just add this cell to the end of the list of Heaps, updating the Next if required _cells.AddLast(newCell); if (Top is null || PriorityComparison(newCell.Priority, Top.Priority) * _directionMultiplier < 0) { Top = newCell; } ++Count; return(newCell); }
public CellLevel( FibonacciHeapCell <TPriority, TValue> cell, int level ) { Cell = cell; Level = level; }
/// <summary> /// Changes the priority of the given <paramref name="cell"/>. /// </summary> /// <param name="cell">Cell to update the priority.</param> /// <param name="newPriority">New priority.</param> public void ChangeKey([NotNull] FibonacciHeapCell <TPriority, TValue> cell, [NotNull] TPriority newPriority) { if (cell is null) { throw new ArgumentNullException(nameof(cell)); } ChangeKeyInternal(cell, newPriority, false); }
/// <summary> /// Deletes the given <paramref name="cell"/> from this heap. /// </summary> /// <param name="cell">Cell to delete.</param> public void Delete([NotNull] FibonacciHeapCell <TPriority, TValue> cell) { if (cell is null) { throw new ArgumentNullException(nameof(cell)); } ChangeKeyInternal(cell, default(TPriority), true); Dequeue(); }
IEnumerator <FibonacciHeapCell <TPriority, TValue> > GetEnumerator() { FibonacciHeapCell <TPriority, TValue> current = First; while (current != null) { yield return(current); current = current.Next; } }
public TVertex Dequeue() { FibonacciHeapCell <TDistance, TVertex> cell = _heap.Top; if (cell is null) { throw new InvalidOperationException("Queue is empty."); } _heap.Dequeue(); return(cell.Value); }
private void CompressHeap() { FibonacciHeapCell <TPriority, TValue> cell = _cells.First; while (cell != null) { var nextCell = ReduceCell(ref cell); _degreeToCell[cell.Degree] = cell; cell = nextCell; } }
private void UpdateCellSameDirection( [NotNull] FibonacciHeapCell <TPriority, TValue> cell, [CanBeNull] TPriority newKey, bool deletingCell) { cell.Priority = newKey; FibonacciHeapCell <TPriority, TValue> parentCell = cell.Parent; if (parentCell != null && (PriorityComparison(newKey, parentCell.Priority) * _directionMultiplier < 0 || deletingCell)) { cell.Marked = false; // ReSharper disable once PossibleNullReferenceException // Justification: parentCell must have children because child has parentCell as Parent. parentCell.Children.Remove(cell); UpdateCellsDegree(parentCell); cell.Parent = null; _cells.AddLast(cell); // This loop is the cascading cut, we continue to cut // ancestors of the cell reduced until we hit a root // or we found an unmarked ancestor while (parentCell.Marked && parentCell.Parent != null) { // ReSharper disable once PossibleNullReferenceException // Justification: parentCell must have children because child has parentCell as Parent. parentCell.Parent.Children.Remove(parentCell); UpdateCellsDegree(parentCell); parentCell.Marked = false; _cells.AddLast(parentCell); FibonacciHeapCell <TPriority, TValue> currentParent = parentCell; parentCell = parentCell.Parent; currentParent.Parent = null; } if (parentCell.Parent != null) { // We mark this cell to note that it had a child // cut from it before parentCell.Marked = true; } } // Update next if (deletingCell || PriorityComparison(newKey, Top.Priority) * _directionMultiplier < 0) { Top = cell; } }
/// <summary> /// Updates the Next pointer, maintaining the heap /// by folding duplicate heap degrees into each other. /// Takes O(log(N)) time amortized. /// </summary> private void UpdateNext() { CompressHeap(); FibonacciHeapCell <TPriority, TValue> cell = _cells.First; Top = cell; while (cell != null) { if (PriorityComparison(cell.Priority, Top.Priority) * _directionMultiplier < 0) { Top = cell; } cell = cell.Next; } }
/// <summary> /// Adds the given <paramref name="cell"/> at the end of this cells list. /// </summary> /// <param name="cell">Cell to add.</param> internal void AddLast([NotNull] FibonacciHeapCell <TPriority, TValue> cell) { Debug.Assert(cell != null); if (_last != null) { _last.Next = cell; } cell.Previous = _last; _last = cell; if (First is null) { First = cell; } }
/// <summary> /// Given two cells, adds the child cell as a child of the parent cell. /// </summary> /// <param name="parentCell">Parent cell.</param> /// <param name="childCell">Child cell.</param> private void ReduceCells( [NotNull] FibonacciHeapCell <TPriority, TValue> parentCell, [NotNull] FibonacciHeapCell <TPriority, TValue> childCell) { Debug.Assert(parentCell != null); Debug.Assert(parentCell.Children != null); Debug.Assert(childCell != null); _cells.Remove(childCell); parentCell.Children.AddLast(childCell); childCell.Parent = parentCell; childCell.Marked = false; if (parentCell.Degree == childCell.Degree) { parentCell.Degree += 1; } }
/// <inheritdoc /> public IEnumerator <KeyValuePair <TPriority, TValue> > GetEnumerator() { var tempHeap = new FibonacciHeap <TPriority, TValue>(Direction, PriorityComparison); var cellsStack = new Stack <FibonacciHeapCell <TPriority, TValue> >(); _cells.ForEach(x => cellsStack.Push(x)); while (cellsStack.Count > 0) { FibonacciHeapCell <TPriority, TValue> topCell = cellsStack.Peek(); tempHeap.Enqueue(topCell.Priority, topCell.Value); cellsStack.Pop(); topCell.Children?.ForEach(x => cellsStack.Push(x)); } while (!tempHeap.IsEmpty) { yield return(tempHeap.Top.ToKeyValuePair()); tempHeap.Dequeue(); } }
/// <summary> /// Merges the given <paramref name="cells"/> at the end of this cells list. /// </summary> /// <param name="cells">Cells to merge.</param> internal void MergeLists([NotNull] FibonacciHeapLinkedList <TPriority, TValue> cells) { Debug.Assert(cells != null); if (cells.First is null) { return; } if (_last != null) { _last.Next = cells.First; } cells.First.Previous = _last; _last = cells._last; if (First is null) { First = cells.First; } }
internal FibonacciHeapLinkedList() { First = null; _last = null; }