fewer lookups in kahn's algorithm

This commit is contained in:
Eric Mertens 2022-11-09 15:45:55 -08:00
parent 35e31bf67f
commit 48da2e2805

View File

@ -45,27 +45,30 @@ auto Parse(std::istream & in) -> Recipes {
auto Topsort(Recipes const& recipes) -> std::vector<std::string> auto Topsort(Recipes const& recipes) -> std::vector<std::string>
{ {
// Kahn's algorithm // Kahn's algorithm
std::set<std::string> perm;
std::set<std::string> temp;
std::vector<std::string> result; std::vector<std::string> result;
result.reserve(recipes.size());
auto visit_ = [&](auto& rec, std::string name) -> void { std::map<std::string, bool> marks; // false temp, true done
if (!perm.contains(name)) { auto const visit = [&](auto const& visit, auto const& name) -> void {
if (!temp.insert(name).second) throw std::runtime_error{"cyclic recipes"}; auto [mark_iterator, is_new] = marks.try_emplace(name, false);
if (recipes.contains(name)) { auto& [_, is_done] = *mark_iterator;
for (auto && [_, c] : recipes.at(name).second) {
rec(rec, c); if (is_new) {
auto const rit = recipes.find(name);
if (rit != recipes.end()) {
for (auto const& [_, c] : rit->second.second) {
visit(visit, c);
} }
} }
temp.erase(name); is_done = true;
perm.insert(name);
result.push_back(name); result.push_back(name);
} else if (!is_done) {
throw std::runtime_error{"cyclic graph"};
} }
}; };
auto visit = [&](auto name) { visit_(visit_, name); };
for (auto && [k,_] : recipes) { for (auto const& [c,_] : recipes) {
visit(k); visit(visit, c);
} }
std::reverse(result.begin(), result.end()); std::reverse(result.begin(), result.end());