#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.Algorithms.DataAnalysis { // TODO: move to HeuristicLab.Collections // Code Taken from branch: RoutePlanning, Heap4 // implementation based on C++ version from Peter Sanders // http://www.mpi-inf.mpg.de/~sanders/programs/spq/ public sealed class PriorityQueue where TK : IComparable { private class KNElement { public TK Key { get; set; } public TV Value { get; set; } } private readonly int capacity; private int size; // index of last used element private int finalLayerSize; // size of first layer with free space private int finalLayerDist; // distance to end of layer //private KNElement[] rawData; private readonly KNElement[] data; // aligned version of rawData public PriorityQueue(TK supremum, TK infimum, int cap) { capacity = cap; data = Enumerable.Range(0, capacity + 4).Select(x => new KNElement()).ToArray(); data[0].Key = infimum; // sentinel data[capacity + 1].Key = supremum; data[capacity + 2].Key = supremum; data[capacity + 3].Key = supremum; Reset(); } public int Size { get { return size; } } public TK Supremum { get { return data[capacity + 1].Key; } } public KeyValuePair PeekMin() { if(size == 0) { throw new InvalidOperationException("Heap is empty"); } return new KeyValuePair(data[1].Key, data[1].Value); } public TK PeekMinKey() { return data[1].Key; } public TV PeekMinValue() { return data[1].Value; } public void RemoveMin() { // first move up elements on a min-path var hole = 1; var succ = 2; var layerSize = 4; var layerPos = 0; var sz = size; size = sz - 1; finalLayerDist++; if(finalLayerDist == finalLayerSize) { finalLayerSize >>= 2; finalLayerDist = 0; } while(succ < sz) { var minKey = data[succ].Key; var delta = 0; var otherKey = data[succ + 1].Key; if(otherKey.CompareTo(minKey) < 0) { minKey = otherKey; delta = 1; } otherKey = data[succ + 2].Key; if(otherKey.CompareTo(minKey) < 0) { minKey = otherKey; delta = 2; } otherKey = data[succ + 3].Key; if(otherKey.CompareTo(minKey) < 0) { minKey = otherKey; delta = 3; } succ += delta; layerPos += delta; // move min successor up data[hole].Key = minKey; data[hole].Value = data[succ].Value; // step to next layer hole = succ; succ = succ - layerPos + layerSize; // beginning of next layer layerPos <<= 2; succ += layerPos; // now correct value layerSize <<= 2; } // bubble up rightmost element var bubble = data[sz].Key; layerSize >>= 2; // now size of hole's layer layerPos >>= 2; // now pos of hole within its layer var layerDist = layerSize - layerPos - 1; // hole's dist to end of layer var pred = hole + layerDist - layerSize; // end of pred's layer for now layerSize >>= 2; // now size of pred's layer layerDist >>= 2; // now pred's pos in layer pred = pred - layerDist; // finally preds index while(data[pred].Key.CompareTo(bubble) > 0) { // must terminate since inf at root data[hole].Key = data[pred].Key; data[hole].Value = data[pred].Value; hole = pred; pred = hole + layerDist - layerSize; // end of hole's layer for now layerSize >>= 2; layerDist >>= 2; pred = pred - layerDist; // finally preds index } // finally move data to hole data[hole].Key = bubble; data[hole].Value = data[sz].Value; data[sz].Key = Supremum; // mark as deleted } public void Insert(TK key, TV value) { var layerSize = finalLayerSize; var layerDist = finalLayerDist; finalLayerDist--; if(finalLayerDist == -1) { // layer full // start next layer finalLayerSize <<= 2; finalLayerDist = finalLayerSize - 1; } size++; var hole = size; var pred = hole + layerDist - layerSize; // end of pred's layer for now layerSize >>= 2; // now size of pred's layer layerDist >>= 2; pred = pred - layerDist; // finally preds index var predKey = data[pred].Key; while(predKey.CompareTo(key) > 0) { data[hole].Key = predKey; data[hole].Value = data[pred].Value; hole = pred; pred = hole + layerDist - layerSize; // end of pred's layer for now layerSize >>= 2; // now isze of pred's layer layerDist >>= 2; pred = pred - layerDist; // finally preds index predKey = data[pred].Key; } // finally move data to hole data[hole].Key = key; data[hole].Value = value; } // reset size to 0 and fill data array with sentinels private void Reset() { size = 0; finalLayerSize = 1; finalLayerDist = 0; var sup = Supremum; var cap = capacity; for(var i = 1; i <= cap; i++) { data[i].Key = sup; } } } }