From bdc720694ffa190907c3c4dd9815404b3ecab10c Mon Sep 17 00:00:00 2001 From: Michael Mandl Date: Wed, 20 Mar 2024 15:05:25 +0100 Subject: [PATCH] feat: add tree-finder --- QVectorSearch/mainwindow.cpp | 4 ++ lib_vector_search/CMakeLists.txt | 14 ++++++- lib_vector_search/include/tree_finder.h | 34 ++++++++++++++++ lib_vector_search/src/tree_finder.cpp | 53 +++++++++++++++++++++++++ vector_search_cli/main.cpp | 24 +++++++++-- 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 lib_vector_search/include/tree_finder.h create mode 100644 lib_vector_search/src/tree_finder.cpp diff --git a/QVectorSearch/mainwindow.cpp b/QVectorSearch/mainwindow.cpp index 545b0a2..e106b8d 100644 --- a/QVectorSearch/mainwindow.cpp +++ b/QVectorSearch/mainwindow.cpp @@ -5,6 +5,7 @@ #include "linear_finder.h" #include "parallel_finder.h" #include "timer.h" +#include "tree_finder.h" #include "word_list_generator.h" #include @@ -26,6 +27,7 @@ MainWindow::~MainWindow() { delete ui; } void MainWindow::setupAlgorithmSelector() { search_algorithms_.appendRow(new QStandardItem("Linear search")); search_algorithms_.appendRow(new QStandardItem("Parallel search")); + search_algorithms_.appendRow(new QStandardItem("Tree search")); } void MainWindow::generateWordList() { @@ -68,6 +70,8 @@ std::unique_ptr MainWindow::createSelectedFinder() const { case 1: return std::make_unique( word_list_, std::thread::hardware_concurrency()); + case 2: + return std::make_unique(word_list_); } } diff --git a/lib_vector_search/CMakeLists.txt b/lib_vector_search/CMakeLists.txt index edb6b42..6c00ac7 100644 --- a/lib_vector_search/CMakeLists.txt +++ b/lib_vector_search/CMakeLists.txt @@ -5,8 +5,18 @@ project( VERSION 0.1.0 LANGUAGES CXX) -add_library(vector_search STATIC src/word_list_generator.cpp src/timer.cpp - src/linear_finder.cpp src/parallel_finder.cpp) +add_library( + vector_search STATIC + src/word_list_generator.cpp + include/word_list_generator.h + src/timer.cpp + include/timer.h + src/linear_finder.cpp + include/linear_finder.h + src/parallel_finder.cpp + include/parallel_finder.h + src/tree_finder.cpp + include/tree_finder.h) target_include_directories(vector_search PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/lib_vector_search/include/tree_finder.h b/lib_vector_search/include/tree_finder.h new file mode 100644 index 0000000..6117573 --- /dev/null +++ b/lib_vector_search/include/tree_finder.h @@ -0,0 +1,34 @@ +#pragma once + +#include "finder.h" + +#include +#include + +class SearchTreeNode { +private: + std::forward_list words_; + std::map children_; + +public: + void insert(std::string_view partial_word, const string *original_word); + const SearchTreeNode *find(std::string_view search_term) const; + + std::forward_list words() const; +}; + +class SearchTree : public SearchTreeNode { +public: + SearchTree(const std::vector &word_list); +}; + +class TreeFinder : public Finder { +private: + SearchTree search_tree_; + +public: + TreeFinder(const std::vector &word_list); + + virtual std::forward_list + find_prefix(std::string_view search_term) const override; +}; diff --git a/lib_vector_search/src/tree_finder.cpp b/lib_vector_search/src/tree_finder.cpp new file mode 100644 index 0000000..9b94682 --- /dev/null +++ b/lib_vector_search/src/tree_finder.cpp @@ -0,0 +1,53 @@ +#include "tree_finder.h" + +void SearchTreeNode::insert(std::string_view partial_word, + const string *original_word) { + if (partial_word.empty()) { + words_.push_front(original_word); + } else { + children_[partial_word.front()].insert( + std::string_view(partial_word).substr(1, partial_word.length()), + original_word); + } +} + +const SearchTreeNode *SearchTreeNode::find(std::string_view search_term) const { + if (search_term.empty()) { + return this; + } + + auto child = children_.find(search_term.front()); + if (child != children_.cend()) { + return child->second.find(search_term.substr(1, search_term.length())); + } + + return nullptr; +} + +std::forward_list SearchTreeNode::words() const { + std::forward_list results(words_); + for (const auto &child : children_) { + results.merge(child.second.words()); + } + + return results; +}; + +SearchTree::SearchTree(const std::vector &word_list) { + for (const auto &word : word_list) { + insert(std::string_view(word), &word); + } +} + +TreeFinder::TreeFinder(const std::vector &word_list) + : search_tree_(word_list) {} + +std::forward_list +TreeFinder::find_prefix(std::string_view search_term) const { + const auto *result_node = search_tree_.find(search_term); + if (result_node == nullptr) { + return {}; + } + + return result_node->words(); +} diff --git a/vector_search_cli/main.cpp b/vector_search_cli/main.cpp index dd7682e..0d31e5b 100644 --- a/vector_search_cli/main.cpp +++ b/vector_search_cli/main.cpp @@ -1,6 +1,7 @@ #include "linear_finder.h" #include "parallel_finder.h" #include "timer.h" +#include "tree_finder.h" #include "word_list_generator.h" #include @@ -26,9 +27,7 @@ vector generate_word_list() { void test_linear_finder(const vector &word_list) { cout << "\nrunning linear finder" << endl; - Timer constructor_timer; LinearFinder linear_finder(word_list); - constructor_timer.stop(); Timer find_timer; auto result = linear_finder.find_prefix("ABCD"); @@ -46,9 +45,7 @@ void test_parallel_finder(const vector &word_list) { cout << "using " << thread_count << " threads" << endl; - Timer constructor_timer; ParallelFinder parallel_finder(word_list, thread_count); - constructor_timer.stop(); Timer find_timer; auto result = parallel_finder.find_prefix("ABCD"); @@ -59,6 +56,24 @@ void test_parallel_finder(const vector &word_list) { << " element(s) long" << endl; } +void test_tree_finder(const vector &word_list) { + cout << "\nrunning tree finder" << endl; + + Timer constructor_timer; + TreeFinder tree_finder(word_list); + constructor_timer.stop(); + + cout << "tree finder constructor took " << constructor_timer << endl; + + Timer find_timer; + auto result = tree_finder.find_prefix("ABCD"); + find_timer.stop(); + + cout << "tree finder took " << find_timer << endl; + cout << "result list is " << std::distance(result.cbegin(), result.cend()) + << " element(s) long" << endl; +} + int main(int argc, char *argv[]) { cout << "\n== VectorSearch ==" << endl; @@ -66,6 +81,7 @@ int main(int argc, char *argv[]) { test_linear_finder(word_list); test_parallel_finder(word_list); + test_tree_finder(word_list); return EXIT_SUCCESS; }