Refactor: Replace std::map and std::set with unordered versions

This commit is contained in:
stefiosif
2022-10-12 17:26:11 +03:00
parent c525aeaa43
commit dc7fa93a6a
13 changed files with 44 additions and 41 deletions

View File

@@ -14,24 +14,24 @@ class BreadthFirstSearch {
public: public:
BreadthFirstSearch() = default; BreadthFirstSearch() = default;
BreadthFirstSearch(std::map<T, std::set<T>> adjList) BreadthFirstSearch(std::unordered_map<T, std::unordered_set<T>> adjList)
: adjList(adjList) {} : adjList(adjList) {}
// Traverse whole graph using the BFS search, and save the tree graph // Traverse whole graph using the BFS search, and save the tree graph
// which is created when visiting new vertices (Breadth First Tree) // which is created when visiting new vertices (Breadth First Tree)
std::map<T, std::set<T>> execute(const T& root); std::unordered_map<T, std::unordered_set<T>> execute(const T& root);
// Search if target vertex exists in graph // Search if target vertex exists in graph
bool query(const T& root, const T& target); bool query(const T& root, const T& target);
private: private:
// Represents the graph on which the algorithm will be executed // Represents the graph on which the algorithm will be executed
std::map<T, std::set<T>> adjList; std::unordered_map<T, std::unordered_set<T>> adjList;
}; };
template<typename T> template<typename T>
std::map<T, std::set<T>> BreadthFirstSearch<T>::execute(const T& root) { std::unordered_map<T, std::unordered_set<T>> BreadthFirstSearch<T>::execute(const T& root) {
std::map<T, std::set<T>> tree; std::unordered_map<T, std::unordered_set<T>> tree;
std::map<T, bool> visited; std::unordered_map<T, bool> visited;
std::queue<T> Q; std::queue<T> Q;
Q.push(root); Q.push(root);
visited[root] = true; visited[root] = true;
@@ -54,7 +54,7 @@ std::map<T, std::set<T>> BreadthFirstSearch<T>::execute(const T& root) {
template<typename T> template<typename T>
bool BreadthFirstSearch<T>::query(const T& root, const T& target) { bool BreadthFirstSearch<T>::query(const T& root, const T& target) {
std::map<T, bool> visited; std::unordered_map<T, bool> visited;
std::queue<T> Q; std::queue<T> Q;
Q.push(root); Q.push(root);
visited[root] = true; visited[root] = true;

View File

@@ -31,10 +31,10 @@ public:
void remove(const std::vector<std::pair<T, T>>& edges); void remove(const std::vector<std::pair<T, T>>& edges);
private: private:
// Transitive closure matrix, used to answer reachability queries in O(1) // Transitive closure matrix, used to answer reachability queries in O(1)
std::map<T, std::map<T, bool>> TC; std::unordered_map<T, std::unordered_map<T, bool>> TC;
// For each SCC, store a reachability tree created as a BFS tree // For each SCC, store a reachability tree created as a BFS tree
std::map<T, BreadthFirstTree<T>> RT; std::unordered_map<T, BreadthFirstTree<T>> RT;
// For each SCC, store collections of incoming, outgoing and internal edges // For each SCC, store collections of incoming, outgoing and internal edges
struct Edges { struct Edges {
@@ -42,7 +42,7 @@ private:
std::set<std::pair<T, T>> inc; std::set<std::pair<T, T>> inc;
std::set<std::pair<T, T>> out; std::set<std::pair<T, T>> out;
}; };
std::map<T, Edges> E; std::unordered_map<T, Edges> E;
// Decremental maintenance of strongly connected components // Decremental maintenance of strongly connected components
RodittyZwick<T> rodittyZwick; RodittyZwick<T> rodittyZwick;
@@ -101,7 +101,7 @@ void Frigioni<T>::remove(const std::vector<std::pair<T, T>>& edges) {
Eext.push_back({ u, v }); Eext.push_back({ u, v });
} }
std::map<T, std::stack<T>> H; std::unordered_map<T, std::stack<T>> H;
for (const auto& [u, v] : Eint) { for (const auto& [u, v] : Eint) {
this->G.remove(u, v); this->G.remove(u, v);
rodittyZwick.remove(u, v); rodittyZwick.remove(u, v);

View File

@@ -47,8 +47,8 @@ private:
std::set<T> S; std::set<T> S;
// Maintain in-out bfs trees // Maintain in-out bfs trees
std::map<T, BreadthFirstTree<T>> In; std::unordered_map<T, BreadthFirstTree<T>> In;
std::map<T, BreadthFirstTree<T>> Out; std::unordered_map<T, BreadthFirstTree<T>> Out;
}; };
template<typename T> template<typename T>

View File

@@ -28,20 +28,20 @@ public:
void remove(const T& u, const T& v) override; void remove(const T& u, const T& v) override;
private: private:
// Transitive closure matrix // Transitive closure matrix
std::map<T, std::map<T, bool>> TC; std::unordered_map<T, std::unordered_map<T, bool>> TC;
// For each vertex, store a reachability tree created as a BFS tree // For each vertex, store a reachability tree created as a BFS tree
std::map<T, BreadthFirstTree<T>> RT; std::unordered_map<T, BreadthFirstTree<T>> RT;
// For each vertex, store collections of its incoming and outgoing edges // For each vertex, store collections of its incoming and outgoing edges
struct Edges { struct Edges {
std::set<T> inc; std::set<T> inc;
std::set<T> out; std::set<T> out;
}; };
std::map<T, Edges> E; std::unordered_map<T, Edges> E;
// Repair reachability trees after edge deletions // Repair reachability trees after edge deletions
void repairTrees(std::map<T, std::stack<T>>& H); void repairTrees(std::unordered_map<T, std::stack<T>>& H);
}; };
template<typename T> template<typename T>
@@ -68,7 +68,7 @@ template<typename T>
void Italiano<T>::remove(const T& u, const T& v) { void Italiano<T>::remove(const T& u, const T& v) {
if (!this->G.adjList[u].contains(v)) return; if (!this->G.adjList[u].contains(v)) return;
std::map<T, std::stack<T>> H; std::unordered_map<T, std::stack<T>> H;
for (const auto& w : this->G.vertices()) { for (const auto& w : this->G.vertices()) {
if (RT[w].contains(u, v)) { if (RT[w].contains(u, v)) {
if (E[v].inc.size() > 1) if (E[v].inc.size() > 1)
@@ -89,7 +89,7 @@ void Italiano<T>::remove(const T& u, const T& v) {
} }
template<typename T> template<typename T>
void Italiano<T>::repairTrees(std::map<T, std::stack<T>>& H) { void Italiano<T>::repairTrees(std::unordered_map<T, std::stack<T>>& H) {
for (const auto& z : this->G.vertices()) { for (const auto& z : this->G.vertices()) {
while (H[z].size() > 0) { while (H[z].size() > 0) {
const auto& h = H[z].top(); const auto& h = H[z].top();

View File

@@ -31,8 +31,8 @@ public:
void insert(const T& u, const T& v) override; void insert(const T& u, const T& v) override;
private: private:
// Connect each reachabiliy tree with decremental maintenance data structure // Connect each reachabiliy tree with decremental maintenance data structure
std::map<T, Italiano<T>> In; std::unordered_map<T, Italiano<T>> In;
std::map<T, Italiano<T>> Out; std::unordered_map<T, Italiano<T>> Out;
}; };
template<typename T> template<typename T>

View File

@@ -28,17 +28,17 @@ public:
// Remove edge (u,v) and update A accordingly for fast checking query // Remove edge (u,v) and update A accordingly for fast checking query
void remove(const T& u, const T& v) override; void remove(const T& u, const T& v) override;
std::map<T, SCC<T>> getSCCs() { return C; } std::unordered_map<T, SCC<T>> getSCCs() { return C; }
private: private:
// Array used to answer strong connectivity queries in O(1) time // Array used to answer strong connectivity queries in O(1) time
std::map<T, T> A; std::unordered_map<T, T> A;
// Connect each representative with its SCC // Connect each representative with its SCC
std::map<T, SCC<T>> C; std::unordered_map<T, SCC<T>> C;
// Maintain in-out bfs trees // Maintain in-out bfs trees
std::map<T, BreadthFirstTree<T>> In; std::unordered_map<T, BreadthFirstTree<T>> In;
std::map<T, BreadthFirstTree<T>> Out; std::unordered_map<T, BreadthFirstTree<T>> Out;
}; };
template<typename T> template<typename T>

View File

@@ -16,7 +16,7 @@ class Tarjan {
public: public:
Tarjan() = default; Tarjan() = default;
Tarjan(std::map<T, std::set<T>> adjList) : adjList(adjList) {} Tarjan(std::unordered_map<T, std::unordered_set<T>> adjList) : adjList(adjList) {}
// //
auto execute(); auto execute();
@@ -24,7 +24,7 @@ public:
// //
void strongConnect(const T& u); void strongConnect(const T& u);
private: private:
std::map<T, std::set<T>> adjList; std::unordered_map<T, std::unordered_set<T>> adjList;
std::stack<T> S; std::stack<T> S;
std::int16_t index = 0; std::int16_t index = 0;
std::vector<SCC<T>> SCCs; std::vector<SCC<T>> SCCs;
@@ -35,7 +35,7 @@ private:
int lowlink = -1; int lowlink = -1;
bool onStack = false; bool onStack = false;
}; };
std::map<T, Vertex> vmap; std::unordered_map<T, Vertex> vmap;
}; };
template<typename T> template<typename T>
@@ -55,7 +55,7 @@ void Tarjan<T>::strongConnect(const T& u) {
// If u is a root node, pop the stack and generate an SCC // If u is a root node, pop the stack and generate an SCC
if (vmap[u].lowlink == vmap[u].index) { if (vmap[u].lowlink == vmap[u].index) {
std::map<T, std::set<T>> scc; std::unordered_map<T, std::unordered_set<T>> scc;
bool finished = false; bool finished = false;
cid = S.top(); cid = S.top();

View File

@@ -10,7 +10,7 @@ class BreadthFirstTree : public Digraph<T> {
public: public:
BreadthFirstTree() = default; BreadthFirstTree() = default;
BreadthFirstTree(std::map<T, std::set<T>> G, T root) BreadthFirstTree(std::unordered_map<T, std::unordered_set<T>> G, T root)
: BreadthFirstTree<T>(Digraph<T>(G), root) {} : BreadthFirstTree<T>(Digraph<T>(G), root) {}
BreadthFirstTree(Digraph<T> G, T root); BreadthFirstTree(Digraph<T> G, T root);

View File

@@ -11,7 +11,7 @@ class Digraph : public Graph<T> {
public: public:
Digraph() = default; Digraph() = default;
Digraph(std::map<T, std::set<T>> G); Digraph(std::unordered_map<T, std::unordered_set<T>> G);
// Return true if there is a path from u to v // Return true if there is a path from u to v
bool contains(const T& u, const T& v); bool contains(const T& u, const T& v);
@@ -27,7 +27,7 @@ public:
}; };
template<typename T> template<typename T>
Digraph<T>::Digraph(std::map<T, std::set<T>> G) { Digraph<T>::Digraph(std::unordered_map<T, std::unordered_set<T>> G) {
this->adjList = G; this->adjList = G;
} }
@@ -49,7 +49,7 @@ void Digraph<T>::remove(const T& u, const T& v) {
template<typename T> template<typename T>
auto Digraph<T>::reverse() { auto Digraph<T>::reverse() {
std::map<T, std::set<T>> revMatrix; std::unordered_map<T, std::unordered_set<T>> revMatrix;
for (const auto& u : this->vertices()) { for (const auto& u : this->vertices()) {
for (const auto& v : this->adjList[u]) { for (const auto& v : this->adjList[u]) {

View File

@@ -1,8 +1,8 @@
#ifndef GRAPH_H_ #ifndef GRAPH_H_
#define GRAPH_H_ #define GRAPH_H_
#include <map> #include <unordered_map>
#include <set> #include <unordered_set>
#include <ostream> #include <ostream>
#include <ranges> #include <ranges>
@@ -36,7 +36,7 @@ public:
std::uint16_t E(); std::uint16_t E();
// Adjacency matrix representation // Adjacency matrix representation
std::map<T, std::set<T>> adjList; std::unordered_map<T, std::unordered_set<T>> adjList;
friend std::ostream& operator<<<>(std::ostream& os, Graph<T>& G); friend std::ostream& operator<<<>(std::ostream& os, Graph<T>& G);
}; };

View File

@@ -13,7 +13,8 @@ class SCC : public Digraph<T> {
public: public:
SCC() = default; SCC() = default;
SCC(std::map<T, std::set<T>> G, T id) : Digraph<T>(G), id(id) { normalize(); } SCC(std::unordered_map<T, std::unordered_set<T>> G, T id)
: Digraph<T>(G), id(id) { normalize(); }
SCC(Digraph<T> G, T id) : id(id) { normalize(); } SCC(Digraph<T> G, T id) : id(id) { normalize(); }

View File

@@ -109,7 +109,8 @@ TEST_SUITE("Algorithm") {
auto tree = auto tree =
algo::BreadthFirstSearch<std::uint16_t>(G.adjList).execute(1); algo::BreadthFirstSearch<std::uint16_t>(G.adjList).execute(1);
std::map<std::uint16_t, std::set<std::uint16_t>> expected = { std::unordered_map<std::uint16_t,
std::unordered_set<std::uint16_t>> expected = {
{1, {2}}, {1, {2}},
{2, {3, 6}}, {2, {3, 6}},
{3, {4}}, {3, {4}},

View File

@@ -39,7 +39,8 @@ TEST_SUITE("Graph") {
auto reverse = G.reverse(); auto reverse = G.reverse();
std::map<std::uint16_t, std::set<std::uint16_t>> expected = { std::unordered_map<std::uint16_t,
std::unordered_set<std::uint16_t>> expected = {
{1, {3}}, {1, {3}},
{2, {1}}, {2, {1}},
{3, {2, 5}}, {3, {2, 5}},