/// <summary>Kruskal algorithm.</summary>
        /// <param name="graph">Undirected weighted graph</param>
        /// <returns>Minimal spanning tree</returns>
        public static IUndirectedGraph <TVertexId, TVertexProperty, TEdgeProperty> Kruskal <TVertexId, TVertexProperty, TEdgeProperty>(
            this IUndirectedGraph <TVertexId, TVertexProperty, TEdgeProperty> graph)
            where TEdgeProperty : IWeighted
        {
            var mst = new UndirectedSimpleGraph <TVertexId, TVertexProperty, TEdgeProperty>(
                graph.Vertices.Select(v => v.Id).ToArray());
            var vertexSets = new DisjointSets <Vertex <TVertexId> >(graph.Vertices);
            var edgeHeap   = new Heap <Edge <TVertexId> >(
                (edge1, edge2) => graph.Properties[edge1].Weight.CompareTo(graph.Properties[edge2].Weight)
                );

            foreach (Edge <TVertexId> edge in graph.Edges)
            {
                edgeHeap.Push(edge);
            }

            while (vertexSets.Count > 1 && edgeHeap.Count > 0)
            {
                Edge <TVertexId> edge = edgeHeap.Pop();

                if (!vertexSets.IsSameSet(edge.Source, edge.Destination))
                {
                    mst.AddEdge(edge, graph.Properties[edge]);
                }

                vertexSets.UnionSet(edge.Source, edge.Destination);
            }

            return(mst);
        }