Skip to content

Commit

Permalink
Modified: change *Path fcuntion to const version and change it's retu…
Browse files Browse the repository at this point in the history
…rn type.
  • Loading branch information
huanmie committed Jul 21, 2022
1 parent bc63ee5 commit 6d8cad4
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 42 deletions.
16 changes: 12 additions & 4 deletions Graph/Example.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <cassert>
#include <limits>
#include <numeric>
#include <iostream>
#include <algorithm>
#include <execution>
#include <functional>
Expand All @@ -16,19 +17,26 @@ int main()
{ "D", 2, "E" }, { "D", 5, "B" }, { "C", 4, "E" },
{ "B", 2, "F" }, { "F", 1, "E" }, { "C", 5, "F" },
});

graph.AddEdge("C", "D") = 3;
auto out_path = graph.GetOutPath("C");
out_path.clear();
graph.RemoveEdge("C", "D");
bool not_exist = graph.AddEdge("C", "D") == graph.INFINITE;
assert(not_exist);
graph.GetOutPath("C", [&out_path](auto&& new_path) {out_path.push_back(new_path); return true; });
graph.GetOutPath("C", [](auto&& new_path) {std::cout << "C->" << new_path.first << '\n'; return true; });

auto in_path = graph.GetInPath("B");
in_path.clear();
graph.GetInPath("B", [&in_path](auto&& new_path) {in_path.push_back(new_path); return true; });
std::vector<decltype(graph)::PathType> copy_results;
graph.GetInPath("B", [&copy_results](auto&& new_path) {copy_results.push_back(new_path); return true; });

auto weight = graph.AddEdge("C", "E");
not_exist = graph.AddEdge("C", "T") == graph.INFINITE;
assert(not_exist);

auto result = graph.GetBestPath("A", "E");

if (graph.CacheSize() > 0)
graph.ClearCache();

return 0;
}
87 changes: 49 additions & 38 deletions Graph/Graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@
template<typename Vertex, typename Weight = int>
class Graph
{
public:
using PathType = std::unordered_map<Vertex, Weight>::value_type;
using ResultsType = std::vector<std::reference_wrapper<const PathType>>;
using ComparatorType = bool(*)(const Weight&, const Weight&);
using BestPathType = ResultsType(const Graph<Vertex, Weight>*, const Vertex&, const Vertex&, ComparatorType);

private:
template<typename T>
struct Allocator :public std::allocator<T>
{
void construct(std::same_as<PathType> auto* p, auto&& tag, auto&& key_tuple, auto&& value_tuple)
{
assert(std::tuple_size_v<std::remove_reference_t<decltype(value_tuple)>> == 0);
::new((void*)p) PathType(std::forward<decltype(tag)>(tag),
::new(p) PathType(std::forward<decltype(tag)>(tag),
std::forward<decltype(key_tuple)>(key_tuple),
std::forward_as_tuple(Graph<Vertex, Weight>::INFINITE));
}

template<class U>
template<typename U>
void destroy(U* p)
{
p->~U();
Expand All @@ -31,9 +36,8 @@ class Graph

using AdjacencyMatrix = std::unordered_map<Vertex, std::unordered_map<Vertex, Weight, std::hash<Vertex>, std::equal_to<Vertex>, Allocator<PathType>>>;
AdjacencyMatrix matrix;

using Compare = bool(*)(const Weight&, const Weight&);
std::function<std::vector<PathType>(const Vertex&, const Vertex&, Compare)> best_path;
mutable std::unordered_map<Vertex, Weight> cache;
std::function<BestPathType> best_path;

public:
static Weight INFINITE;
Expand Down Expand Up @@ -68,71 +72,78 @@ class Graph
matrix[begin][end] = INFINITE;
}

auto GetOutPath(const Vertex& vertex)
ResultsType GetOutPath(const Vertex& vertex) const
{
std::vector<PathType> results;
for (auto&& element : matrix[vertex])
if (element.second != INFINITE)
results.push_back(element);
ResultsType results;
if (matrix.contains(vertex))
for (auto&& element : matrix.at(vertex))
if (element.second != INFINITE)
results.emplace_back(element);
return results;
}

void GetOutPath(const Vertex& vertex, std::invocable<PathType> auto&& callback)
requires std::is_same_v<std::invoke_result_t<decltype(callback), PathType>, bool>
void GetOutPath(const Vertex& vertex, std::invocable<const PathType&> auto&& callback) const
requires std::is_same_v<std::invoke_result_t<decltype(callback), const PathType&>, bool>
{
for (auto&& element : matrix[vertex])
if (element.second != INFINITE)
if (!callback(element))
break;
if (matrix.contains(vertex))
for (auto&& element : matrix.at(vertex))
if (element.second != INFINITE)
if (!callback(element))
break;
}

auto GetInPath(const Vertex& vertex)
ResultsType GetInPath(const Vertex& vertex) const
{
std::vector<PathType> results;
ResultsType results;
for (auto iterator = matrix.begin(); iterator != matrix.end(); ++iterator)
if (iterator->second.contains(vertex) && iterator->second[vertex] != INFINITE)
results.push_back({ iterator->first, iterator->second[vertex] });
if (iterator->second.contains(vertex) && iterator->second.at(vertex) != INFINITE)
{
cache[iterator->first] = iterator->second.at(vertex);
results.emplace_back(*cache.find(iterator->first));
}
return results;
}

void GetInPath(const Vertex& vertex, std::invocable<PathType> auto&& callback)
requires std::is_same_v<std::invoke_result_t<decltype(callback), PathType>, bool>
void GetInPath(const Vertex& vertex, std::invocable<const PathType&> auto&& callback) const
requires std::is_same_v<std::invoke_result_t<decltype(callback), const PathType&>, bool>
{
for (auto iterator = matrix.begin(); iterator != matrix.end(); ++iterator)
if (iterator->second.contains(vertex) && iterator->second[vertex] != INFINITE)
if (!callback(PathType{ iterator->first, iterator->second[vertex] }))
if (iterator->second.contains(vertex) && iterator->second.at(vertex) != INFINITE)
if (!callback(PathType{ iterator->first, iterator->second.at(vertex) }))
break;
}

void SetBestPathAlgorithm(std::invocable<const Vertex&, const Vertex&, Compare> auto&& function)
void SetBestPathAlgorithm(std::invocable<const Graph<Vertex, Weight>*, const Vertex&, const Vertex&, ComparatorType> auto&& function)
{
best_path = std::forward<decltype(function)>(function);
}

std::vector<PathType> GetBestPath(const Vertex& begin, const Vertex& end, Compare comparator = [](const Weight& first, const Weight& second) {return first < second; })
ResultsType GetBestPath(const Vertex& begin, const Vertex& end, ComparatorType comparator = [](const Weight& first, const Weight& second) {return first < second; }) const
{
if (best_path)
return best_path(begin, end, comparator);
return best_path(this, begin, end, comparator);
else
{
std::vector<std::vector<PathType>> results;
IterateGraph(results, end, {}, { begin, Weight{} }, {});
std::vector<ResultsType> results;
cache[begin] = Weight{};
IterateGraph(results, end, {}, *cache.find(begin), {});
if (!results.empty())
{
std::vector<std::pair<Weight, std::size_t>> sort_weight;
for (size_t i = 0; i < results.size(); ++i)
sort_weight.emplace_back(
std::accumulate(results[i].begin(), results[i].end(), Weight{}, [](auto&& acc, auto&& pair) {return acc + pair.second; }),
i);
sort_weight.emplace_back(std::accumulate(results[i].begin(), results[i].end(), Weight{}, [](auto&& acc, auto&& pair) {return acc + pair.get().second; }), i);
std::sort(std::execution::par_unseq, sort_weight.begin(), sort_weight.end(), [comparator](auto&& first, auto&& second) {return comparator(first.first, second.first); });
auto& result = results[sort_weight[0].second];
result[0].second = sort_weight[0].first;
return result;
auto& best_result = results[sort_weight[0].second];
cache[begin] = sort_weight[0].first;
return best_result;
}
return {};
}
}

auto CacheSize() { return cache.size(); }
void ClearCache() { cache.clear(); }

private:
void Construct(auto&& vertex1, auto&& weight, auto&& vertex2, auto&&... rests)
{
Expand All @@ -145,7 +156,7 @@ class Graph
AddEdge(std::forward<decltype(vertex1)>(vertex1), std::forward<decltype(vertex2)>(vertex2)) = std::forward<decltype(weight)>(weight);
}

void IterateGraph(std::vector<std::vector<PathType>>& results, const Vertex& target, std::vector<PathType> current_path, PathType new_path, std::unordered_set<Vertex> set)
void IterateGraph(std::vector<ResultsType>& results, const Vertex& target, ResultsType current_path, const PathType& new_path, std::unordered_set<Vertex> set) const
{
set.insert(new_path.first);
current_path.push_back(new_path);
Expand All @@ -156,11 +167,11 @@ class Graph
return;
}

for (auto [vertex, weight] : matrix[new_path.first])
for (auto&& [vertex, weight] : matrix.at(new_path.first))
{
if (set.contains(vertex) || weight == INFINITE)
continue;
IterateGraph(results, target, current_path, { vertex, weight }, set);
IterateGraph(results, target, current_path, *matrix.at(new_path.first).find(vertex), set);
}
}
};
Expand Down

0 comments on commit 6d8cad4

Please sign in to comment.