diff --git a/top_order/top_order.cpp b/top_order/top_order.cpp index 919a60c..4206ea8 100644 --- a/top_order/top_order.cpp +++ b/top_order/top_order.cpp @@ -13,13 +13,8 @@ int main() { int size = 10; Digraph G(size); G.add_edge(3,4); - // G.add_edge(4,3); - // G.add_edge(5,6); G.add_edge(6,7); G.add_edge(7,5); - // G.add_edge(7,3); - // G.add_edge(0,3); - // G.add_edge(3,0); // keeps track of vertices with zero indegree, these can be put at the beginning std::stack zero_indegree; diff --git a/tree_isomorphism/CMakeLists.txt b/tree_isomorphism/CMakeLists.txt new file mode 100644 index 0000000..7b55fc8 --- /dev/null +++ b/tree_isomorphism/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.10) +project(tree_isomorphism) +add_executable(tree_isomorphism + tree_isomorphism.cpp) diff --git a/tree_isomorphism/tree_isomorphism.cpp b/tree_isomorphism/tree_isomorphism.cpp new file mode 100644 index 0000000..0ef19f1 --- /dev/null +++ b/tree_isomorphism/tree_isomorphism.cpp @@ -0,0 +1,175 @@ +// Algorithm deciding if two rooted trees are isomorphic +// Authors: GeorĒµi Kocharyan + +#include +#include +#include +#include +#include +#include +#include + +// Node has to store parent to make naming possible in linear time + +struct TreeNode { + std::vector children; + std::string name; + TreeNode* parent; + TreeNode() = default; + TreeNode(TreeNode* node) : parent(node) {} + void add_child() + { + children.push_back(new TreeNode(this)); + } +}; + +// outputs a vector of lists of each depth of the tree + +std::vector> tree_levels(TreeNode* root) { + if (!root) return {}; + + std::vector> result; + std::queue> q; + q.push(std::make_pair(root, 0)); + + while (!q.empty()) + { + TreeNode* node = q.front().first; + int depth = q.front().second; + q.pop(); + + // If this is a new depth, add a new list to the result + if (depth >= result.size()) { + result.push_back(std::list()); + } + + // Add the current node's value to the appropriate depth list + result[depth].push_back(node); + + // Enqueue children with their depth + for (const auto& child : node->children) { + q.push(std::make_pair(child, depth + 1)); + } + } + return result; +} + +bool lexicographicOrder(TreeNode* a,TreeNode* b) { + return (a->name)<(b->name); +} + +// to do: actually implement linear bucket sort +void bucketSort(std::list& nodes) { + if (nodes.empty()) return; + nodes.sort(lexicographicOrder); +} + +int main() { + + // initialise tree 1 + TreeNode* root = new TreeNode(); + root->add_child(); + root->add_child(); + root->add_child(); + root->children[1]->add_child(); + root->children[1]->add_child(); + root->children[2]->add_child(); + root->children[1]->children[1]->add_child(); + root->children[2]->children[0]->add_child(); + root->children[2]->children[0]->add_child(); + + // initialise tree 2 + TreeNode* root2 = new TreeNode(); + root2->add_child(); + root2->add_child(); + root2->add_child(); + root2->children[0]->add_child(); + root2->children[2]->add_child(); + root2->children[2]->add_child(); + root2->children[0]->children[0]->add_child(); + root2->children[2]->children[1]->add_child(); + root2->children[2]->children[1]->add_child(); + + // store all nodes by their depth + std::vector> levels1 = tree_levels(root); + std::vector> levels2 = tree_levels(root2); + + int height = levels1.size()-1; + + // if heights are different trees cannot be isomorphic + if (!(height == levels2.size()-1)) + { + std::cout << "Trees are not isomorphic. Their heights are different." << std::endl; + return 0; + } + + // the name of all leaves is 1 + std::string s("1"); + + for (auto leaf : levels1[height]) + { + leaf->name = s; + } + for (auto leaf : levels2[height]) + { + leaf->name = s; + } + + for (int i = height-1; i >= 0; i--) + { + int amount = levels1[i].size(); + if (!(amount == levels2[i].size())) + { + std::cout << "Trees are not isomorphic, they have a different number of nodes in depth " << i << "." << std::endl; + return 0; + } + + // name all nodes of current height by iterating through all (sorted) children + + for (const auto& node : levels1[i+1]) + { + node->parent->name = node->parent->name + node->name; + } + + for (const auto& node : levels2[i+1]) + { + node->parent->name = node->parent->name + node->name; + } + + // sort nodes of current height by name + bucketSort(levels1[i]); + bucketSort(levels2[i]); + + // check if both trees have the same names in the current level + std::list::iterator itr1 = levels1[i].begin(); + std::list::iterator itr2 = levels2[i].begin(); + + for (auto _ = amount; _--;) + { + if (!(((*itr1)->name) == ((*itr2)->name))) + { + std::cout << "Trees are not isomorphic!" << std::endl; + return 0; + } + itr1++; + itr2++; + } + + // rename words according to index in sorted vector + int count = 0; + for (auto& node : levels1[i]) + { + node->name = std::to_string(count); + count++; + } + count = 0; + for (auto& node : levels2[i]) + { + node->name = std::to_string(count); + count++; + } + } + + std::cout << "Trees are isomorphic." << std::endl; + return 0; +} \ No newline at end of file