コード例 #1
0
        /// <summary>
        ///     Computes the minimum spanning tree for the connected component containing a specified vertex.
        /// </summary>
        /// <param name="startVertex">The vertex where the algorithm should start.</param>
        /// <returns>The set of edges that define the minimum spanning tree.</returns>
        public ReadOnlySpan <TEdgeId> ComputeMinimumSpanningTree(TVertexId startVertex)
        {
            var heapNodes = new Dictionary <TVertexId, PairingHeap <VertexWithDistanceAndEdge> .ElementPointer>(this._graph.Comparer)
            {
                { startVertex, PairingHeap <VertexWithDistanceAndEdge> .ElementPointer.Undefined }
            };
            var todo   = new PairingHeap <VertexWithDistanceAndEdge>(new DistanceComparer(this._comparer));
            var result = new DynamicArray <TEdgeId>(true);

            ProcessEdges(startVertex);
            while (todo.TryExtractMinimum(out var next))
            {
                heapNodes[next.Vertex] = PairingHeap <VertexWithDistanceAndEdge> .ElementPointer.Undefined;
                result.AddLast(next.Edge);
                ProcessEdges(next.Vertex);
            }

            return(result.AsSpan());

            void ProcessEdges(TVertexId vertex)
            {
                foreach (var outEdgeIdx in this._graph.GetOutEdges(vertex))
                {
                    var target = this._graph.GetTarget(outEdgeIdx);
                    if (heapNodes.TryGetValue(target, out var vertexState))
                    {
                        if (vertexState.IsUndefined)
                        {
                            continue;
                        }

                        var currentBestDistanceToTarget = todo[vertexState].Distance;
                        var distance = this._graph.GetEdgeTag(outEdgeIdx);
                        if (this._comparer.Compare(distance, currentBestDistanceToTarget) >= 0)
                        {
                            continue;
                        }

                        todo.Decrease(vertexState, new(target, distance, outEdgeIdx));
                    }
                    else
                    {
                        var distance = this._graph.GetEdgeTag(outEdgeIdx);
                        var node     = todo.Insert(new(target, distance, outEdgeIdx));
                        heapNodes.Add(target, node);
                    }
                }
            }
        }
コード例 #2
0
        /// <summary>
        ///     Computes the shortest path between two specified vertices.
        /// </summary>
        /// <param name="startVertex">The vertex where the path should start.</param>
        /// <param name="targetVertex">The vertex where the path should end.</param>
        /// <param name="distance">The shortest distance from <paramref name="startVertex"/> to <paramref name="targetVertex"/>.</param>
        /// <returns>The shortest path, represented as a span of edges.</returns>
        /// <exception cref="ArgumentException">There is no path from <paramref name="startVertex"/> to <paramref name="targetVertex"/>.</exception>
        public ReadOnlySpan <TEdgeId> ComputeShortestPath(TVertexId startVertex, TVertexId targetVertex, out TDistance distance)
        {
            var vertices = new Dictionary <TVertexId, VertexInfo>(this._graph.Comparer);
            var queue    = new PairingHeap <TVertexId, TDistance>(this._calculator);

            var startHeapElement = queue.Insert(new(startVertex, this._calculator.Zero));
            var startVertexInfo  = new VertexInfo(this._heuristicDistanceCalculator(startVertex, targetVertex))
            {
                DistanceToVertex = this._calculator.Zero,
                HeapElement      = startHeapElement
            };

            vertices.Add(startVertex, startVertexInfo);

            while (queue.TryExtractMinimum(out var next))
            {
                var currentVertexInfo = vertices[next.Key];
                var distanceSoFar     = currentVertexInfo.DistanceToVertex;
                currentVertexInfo.HeapElement = PairingHeap <KeyValuePair <TVertexId, TDistance> > .ElementPointer.Undefined;
                if (this._graph.Equals(next.Key, targetVertex))
                {
                    distance = distanceSoFar;
                    return(this.ResolveShortestPath(startVertex, targetVertex, vertices));
                }

                var edges = this._graph.GetOutEdges(next.Key);
                foreach (var edgeId in edges)
                {
                    var target          = this._graph.GetTarget(edgeId);
                    var currentDistance = this._calculator.Add(distanceSoFar, this._graph.GetEdgeTag(edgeId));
                    if (vertices.TryGetValue(target, out var vertexInfo))
                    {
                        if (this._calculator.Compare(currentDistance, vertexInfo.DistanceToVertex) >= 0)
                        {
                            continue;
                        }

                        vertexInfo.DistanceToVertex   = currentDistance;
                        vertexInfo.ShortestPathSource = next.Key;
                        vertexInfo.ShortestPathEdge   = edgeId;
                        var priority = this._calculator.Add(currentDistance, vertexInfo.HeuristicDistanceToTarget);
                        if (vertexInfo.HeapElement.IsUndefined)
                        {
                            vertexInfo.HeapElement = queue.Insert(target, priority);
                        }
                        else
                        {
                            queue.Decrease(vertexInfo.HeapElement, priority);
                        }
                    }
                    else
                    {
                        var heuristicDistance = this._heuristicDistanceCalculator(target, targetVertex);
                        var priority          = this._calculator.Add(currentDistance, heuristicDistance);
                        var heapElement       = queue.Insert(target, priority);
                        vertexInfo = new(heuristicDistance)
                        {
                            HeapElement        = heapElement,
                            DistanceToVertex   = currentDistance,
                            ShortestPathSource = next.Key,
                            ShortestPathEdge   = edgeId
                        };
                        vertices.Add(target, vertexInfo);
                    }
                }
            }

            throw new ArgumentException("Target vertex not reachable from start vertex.", nameof(targetVertex));
        }