-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Algorithms: * Kruskal * Prim Changes to be committed: new file: include/Algorithms/SpanningTree/Kruskal.hpp new file: include/Algorithms/SpanningTree/Prim.hpp
- Loading branch information
1 parent
ea8f04c
commit 376d389
Showing
2 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Kruskal.hpp | ||
* | ||
* Created on: Nov 22, 2018 | ||
* Author: Franziska Wegner, Matthias Wolf | ||
*/ | ||
|
||
#ifndef EGOA__ALGORITHMS__SPANNING_TREES__KRUSKAL_HPP | ||
#define EGOA__ALGORITHMS__SPANNING_TREES__KRUSKAL_HPP | ||
|
||
#include "Algorithms/SpanningTree/MST.hpp" | ||
|
||
#include "DataStructures/Container/UnionFind.hpp" | ||
|
||
namespace egoa { | ||
/** | ||
* @brief An implementation of Kruskal's algorithm for finding minimum spanning | ||
* trees. | ||
* | ||
* @code{.cpp} | ||
* Kuskal<TGraph> kruskal(graph, comparator); | ||
* kruskal.Run(); | ||
* Subgraph<TGraph> spanningTree = kruskal.Result(); | ||
* @endcode | ||
* | ||
* @tparam GraphType The type of the graph. | ||
*/ | ||
template<typename GraphType> | ||
class Kruskal final : public MST<GraphType> { | ||
|
||
using TSpanningTree = MST<GraphType>; | ||
using typename TSpanningTree::TGraph; | ||
using typename TSpanningTree::TEdge; | ||
using typename TSpanningTree::TComparator; | ||
|
||
public: | ||
Kruskal(TGraph & graph, | ||
TComparator comparator) | ||
: TSpanningTree(graph, std::move(comparator)) | ||
{} | ||
|
||
virtual ~Kruskal() {} | ||
|
||
/** | ||
* @brief Kruskal's Algorithm | ||
* @details Kruskal's algorithm runs in O(|E| lg |V|) using binary | ||
* heaps and calculates a MST. It uses techniques that are also | ||
* common for connected component algorithms. | ||
* | ||
* Steps: | ||
* 1. Increases the MST by exactly one edge in each iteration | ||
* 2. It starts with |V| components | ||
* 3. In each iteration the number of connected components shrinks by 1 | ||
* 4. To manage the connected components it uses a disjoint-set data structure | ||
* | ||
*/ | ||
virtual inline void Run() override { | ||
UnionFind unionFind( this->Graph().NumberOfVertices() ); | ||
|
||
// Fill vector with edge identifiers | ||
std::vector<Types::edgeId> edges; | ||
edges.reserve(this->Graph().NumberOfEdges()); | ||
this->Graph().template for_all_edge_identifiers<ExecutionPolicy::sequential>([&edges](Types::edgeId id) { | ||
edges.push_back(id); | ||
}); | ||
|
||
// Sort the edges by their weights | ||
std::sort( edges.begin(), edges.end(), this->Comparator()); | ||
|
||
std::vector<Types::edgeId> spanningTreeEdges; | ||
|
||
for ( Types::edgeId edge : edges ) | ||
{ | ||
Types::vertexId source = this->Graph().EdgeAt( edge ).Source(); | ||
Types::vertexId target = this->Graph().EdgeAt( edge ).Target(); | ||
if ( !unionFind.InSameComponent( source, target ) ) { | ||
unionFind.Union( source, target ); | ||
spanningTreeEdges.push_back( edge ); | ||
} | ||
} | ||
|
||
this->SetResult(std::move(spanningTreeEdges)); | ||
} | ||
}; | ||
|
||
} // namespace egoa | ||
|
||
#endif // EGOA__ALGORITHMS__SPANNING_TREES__KRUSKAL_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
* Prim.hpp | ||
* | ||
* Created on: Nov 22, 2018 | ||
* Author: Franziska Wegner, Matthias Wolf | ||
*/ | ||
|
||
#ifndef EGOA__ALGORITHMS__SPANNING_TREES__PRIM_HPP | ||
#define EGOA__ALGORITHMS__SPANNING_TREES__PRIM_HPP | ||
|
||
#include "Algorithms/SpanningTree/MST.hpp" | ||
|
||
#include "DataStructures/Container/Queues/MappingBinaryHeap.hpp" | ||
|
||
namespace egoa { | ||
/** | ||
* @brief An implementation of Prim's algorithm for finding minimum spanning | ||
* trees. | ||
* | ||
* @code{.cpp} | ||
* Prim<TGraph> prim(graph, comparator); | ||
* prim.Run(); | ||
* Subgraph<TGraph> spanningTree = prim.Result(); | ||
* @endcode | ||
* | ||
* @tparam GraphType The type of the graph. | ||
* @tparam WeightType The type of the edge weights. | ||
*/ | ||
template< typename GraphType> | ||
class Prim final : public MST<GraphType> { | ||
|
||
using TSpanningTree = MST<GraphType>; | ||
using typename TSpanningTree::TGraph; | ||
using typename TSpanningTree::TEdge; | ||
using typename TSpanningTree::TComparator; | ||
|
||
public: | ||
Prim(TGraph & graph, | ||
TComparator comparator) | ||
: TSpanningTree( graph, std::move(comparator) ) | ||
{} | ||
|
||
virtual ~Prim() {} | ||
|
||
/** | ||
* @brief Prim's algorithm | ||
* @detail Prim's algorithm is quite similar to Dijkstra's | ||
* algorithm. Prim runs in O(|E| log |V|) using binary heaps. | ||
* While using Fibonacci heaps the running time is then in O(|E| + | ||
* |V| log |V|). The latter is an improvement while |V| << |E|. | ||
* | ||
* Steps: | ||
* 1. While not all vertices are in the MST component | ||
* 2. Relax the incident edges to u if necessary | ||
* 3. Choose the edge that has the minimum weight between | ||
* the grown MST component and the non-MST component, i.e., | ||
* no cycle will be created | ||
* | ||
* @pre This algorithm assumes that the vertex identifiers all lie in | ||
* the interval [0, NumberOfVertices() - 1]. | ||
*/ | ||
virtual inline void Run ( ) override { | ||
Types::count const numberOfVertices = this->Graph().NumberOfVertices(); | ||
|
||
if (numberOfVertices == 0) return; | ||
|
||
std::vector<bool> isVertexInMst( numberOfVertices, false ); | ||
std::vector<bool> visited(numberOfVertices, false); | ||
std::vector<Types::edgeId> edgesInSpanningTree; | ||
|
||
// TODO: Use vector instead of the default unordered_map | ||
MappingBinaryHeap<Types::vertexId, Types::edgeId> heap(this->Comparator()); | ||
|
||
Types::vertexId currentVertex = 0; | ||
visited[currentVertex] = true; | ||
|
||
while (true) { | ||
isVertexInMst[currentVertex] = true; | ||
|
||
// Iterate over all incident edges | ||
this->Graph().template for_all_edges_at<ExecutionPolicy::sequential>( currentVertex, | ||
[&]( TEdge const & edge ) { | ||
Types::vertexId neighbor = edge.Other( currentVertex ); | ||
|
||
// Ignore edges to vertices that have already been included in the MST | ||
if (isVertexInMst[neighbor]) return; | ||
|
||
if (!visited[neighbor]) | ||
{ // The neighbor has not been visited before | ||
heap.Insert(neighbor, edge.Identifier()); | ||
visited[neighbor] = true; | ||
} else if ( this->Comparator()( edge.Identifier(), heap.KeyOf(neighbor) ) ) | ||
{ | ||
// Better edge to neighbor has been found | ||
heap.ChangeKey(neighbor, edge.Identifier()); | ||
} | ||
}); | ||
|
||
if (heap.Empty()) break; | ||
|
||
Types::edgeId parentEdge; | ||
std::tie(currentVertex, parentEdge) = heap.DeleteTop(); | ||
edgesInSpanningTree.push_back(parentEdge); | ||
} // while loop | ||
|
||
this->SetResult(std::move(edgesInSpanningTree)); | ||
} | ||
}; | ||
|
||
} // namespace egoa | ||
|
||
|
||
#endif // EGOA__ALGORITHMS__SPANNING_TREES__PRIM_HPP |