From 3a5ba7daf8759ce0a893bab994304e5f125972cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Uhl=C3=ADk?= <jan@uhlik.me> Date: Thu, 29 Mar 2018 21:04:15 +0200 Subject: [PATCH] Add Jarkni-Prim algorithm. --- .../src/spanning_tree/JarnikPrim.cpp | 22 ++++ .../src/spanning_tree/JarnikPrim.hpp | 110 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 alib2graph_algo/src/spanning_tree/JarnikPrim.cpp create mode 100644 alib2graph_algo/src/spanning_tree/JarnikPrim.hpp diff --git a/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp b/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp new file mode 100644 index 0000000000..db6d6ea828 --- /dev/null +++ b/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp @@ -0,0 +1,22 @@ +// JarnikPrim.cpp +// +// Created on: 19. 03. 2018 +// Author: Jan Uhlik +// Modified by: +// +// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved. +// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library + +#include "JarnikPrim.hpp" + +#include <registration/AlgoRegistration.hpp> +namespace { + +// --------------------------------------------------------------------------------------------------------------------- +// uni-directional + +auto JarnikPrim1 = registration::AbstractRegister<spanning_tree::JarnikPrim, + graph::WeightedUndirectedGraph<>, + const graph::WeightedUndirectedGraph<> &, + const DefaultNodeType &>(spanning_tree::JarnikPrim::findSpanningTree); +} diff --git a/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp b/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp new file mode 100644 index 0000000000..c2900eb003 --- /dev/null +++ b/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp @@ -0,0 +1,110 @@ +// JarnikPrim.hpp +// +// Created on: 19. 03. 2018 +// Author: Jan Uhlik +// Modified by: +// +// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved. +// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library + +#ifndef ALIB2_JARNIKPRIM_HPP +#define ALIB2_JARNIKPRIM_HPP + +#include <alib/pair> +#include <alib/set> +#include <alib/map> + +#include <common/SupportFunction.hpp> + +namespace spanning_tree { + +class JarnikPrim { +// --------------------------------------------------------------------------------------------------------------------- + public: + + template<typename TGraph, typename TNode> + static + TGraph + findSpanningTree(const TGraph &graph, const TNode &start); + +// ===================================================================================================================== + + private: + + template<typename TNode, typename TWeight> + struct Data { + ext::set<ext::pair<TWeight, TNode>> queue; // priority queue + ext::map<TNode, TWeight> g; // distances (aka G score) + ext::map<TNode, TNode> p; // parents + }; + +// --------------------------------------------------------------------------------------------------------------------- + + template<typename TNode, typename TWeight> + inline static void init(JarnikPrim::Data<TNode, TWeight> &data, const TNode &start); + +}; + +// ===================================================================================================================== + +template<typename TGraph, typename TNode> +TGraph JarnikPrim::findSpanningTree(const TGraph &graph, const TNode &start) { + using weight_type = typename TGraph::edge_type::weight_type; + + TGraph res; + Data<TNode, weight_type> data; + + // Init search + init(data, start); + + while (!data.queue.empty()) { + TNode n = data.queue.begin()->second; + data.queue.erase(data.queue.begin()); + + // If not already in spanning tree add it + auto search = data.p.find(n); + if (search != data.p.end()) { + res.addEdge(search->second, n, data.g.at(n)); + } + + for (const auto &s_edge: graph.successorEdges(n)) { + const TNode &s = common::SupportFunction::other(s_edge, n); // successor + + // Calculate new G score + weight_type gscore = s_edge.weight(); + + // Search if the node s was already visited + auto search_d = data.g.find(s); + + // If not or the distance can be improve do relaxation + if (search_d == data.g.end() || search_d->second > gscore) { + // Search if the node s is in OPEN + auto search_q = data.queue.find(ext::make_pair(search_d->second, s)); + if (search_q != data.queue.end()) { + // Erase node from priority queue + data.queue.erase(search_q); + } + + data.g[s] = gscore; + data.p.insert_or_assign(s, n); + data.queue.insert(ext::make_pair(data.g[s], s)); + } + } + } + + return res; +} + +// --------------------------------------------------------------------------------------------------------------------- + +template<typename TNode, typename TWeight> +void JarnikPrim::init(JarnikPrim::Data<TNode, TWeight> &data, const TNode &start) { + data.g[start] = 0; + data.p.insert_or_assign(start, start); + data.queue.insert(ext::make_pair(data.g[start], start)); +} + +// --------------------------------------------------------------------------------------------------------------------- + +} // namespace spanning_tree +#endif //ALIB2_JARNIKPRIM_HPP -- GitLab