diff --git a/QVectorSearch/mainwindow.cpp b/QVectorSearch/mainwindow.cpp index 4967bba..70567a9 100644 --- a/QVectorSearch/mainwindow.cpp +++ b/QVectorSearch/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" +#include "bucket_finder.h" #include "finder.h" #include "grouped_finder.h" #include "linear_finder.h" @@ -32,6 +33,7 @@ void MainWindow::setupAlgorithmSelector() { search_algorithms_.appendRow(new QStandardItem("Parallel search")); search_algorithms_.appendRow(new QStandardItem("Tree search")); search_algorithms_.appendRow(new QStandardItem("Grouped search")); + search_algorithms_.appendRow(new QStandardItem("Bucket search")); } void MainWindow::setupWordListSourceSelector() { @@ -114,6 +116,9 @@ void MainWindow::createSelectedFinder() { case 4: finder_ = std::make_unique(word_list_); break; + case 5: + finder_ = std::make_unique(word_list_); + break; } } diff --git a/lib_vector_search/CMakeLists.txt b/lib_vector_search/CMakeLists.txt index daa98b2..5bc9c1f 100644 --- a/lib_vector_search/CMakeLists.txt +++ b/lib_vector_search/CMakeLists.txt @@ -18,7 +18,9 @@ add_library( src/tree_finder.cpp include/tree_finder.h src/grouped_finder.cpp - include/grouped_finder.h) + include/grouped_finder.h + src/bucket_finder.cpp + include/bucket_finder.h) target_include_directories(vector_search PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/lib_vector_search/include/bucket_finder.h b/lib_vector_search/include/bucket_finder.h new file mode 100644 index 0000000..d4d9626 --- /dev/null +++ b/lib_vector_search/include/bucket_finder.h @@ -0,0 +1,30 @@ +#pragma once + +#include "finder.h" +#include "word_list.h" + +#include + +class Bucket { +private: + std::map groups_; + +public: + Bucket() = default; + + void insert(const WordList &word_list, size_t first_index, size_t last_index); + + std::forward_list + find_prefix(std::string_view search_term) const; +}; + +class BucketFinder : public Finder { +private: + std::vector buckets_; + +public: + BucketFinder(const WordList &word_list); + + std::forward_list + find_prefix(std::string_view search_term) const override; +}; diff --git a/lib_vector_search/include/word_list.h b/lib_vector_search/include/word_list.h index 3c0b5d9..b2365e2 100644 --- a/lib_vector_search/include/word_list.h +++ b/lib_vector_search/include/word_list.h @@ -22,6 +22,7 @@ public: class WordRefList : public std::vector { public: + WordRefList() = default; WordRefList(const WordList &source); static void find_prefix_in_range( diff --git a/lib_vector_search/src/bucket_finder.cpp b/lib_vector_search/src/bucket_finder.cpp new file mode 100644 index 0000000..5d600d0 --- /dev/null +++ b/lib_vector_search/src/bucket_finder.cpp @@ -0,0 +1,84 @@ +#include "bucket_finder.h" + +#include +#include +#include + +void Bucket::insert(const WordList &word_list, size_t first_index, + size_t last_index) { + for (size_t index = first_index; index < last_index; ++index) { + const auto ¤t_word = word_list[index]; + groups_[current_word.front()].push_back(¤t_word); + } +} + +std::forward_list +Bucket::find_prefix(std::string_view search_term) const { + const auto group = groups_.find(search_term.front()); + if (group == groups_.cend()) { + return {}; + } + + std::forward_list result; + for (const auto *word : group->second) { + if (word->starts_with(search_term)) { + result.push_front(word); + } + } + return result; +} + +BucketFinder::BucketFinder(const WordList &word_list) { + if (word_list.empty()) { + return; + } + + const size_t word_list_size = word_list.size(); + const size_t bucket_count = + std::min(std::thread::hardware_concurrency(), word_list_size); + const size_t bucket_size = word_list_size / bucket_count; + + buckets_.resize(bucket_count); + + std::vector insert_threads; + for (auto bucket_index = 0; bucket_index < bucket_count; ++bucket_index) { + const size_t first_index = bucket_index * bucket_size; + const size_t last_index = (bucket_index == bucket_count - 1) + ? word_list_size + : (bucket_index + 1) * bucket_size; + + auto &bucket = buckets_[bucket_index]; + + insert_threads.emplace_back([&bucket, &word_list, first_index, last_index] { + bucket.insert(word_list, first_index, last_index); + }); + } + + for (auto &thread : insert_threads) { + thread.join(); + } +} + +std::forward_list +BucketFinder::find_prefix(std::string_view search_term) const { + std::forward_list result; + std::mutex result_mutex; + + std::vector search_threads; + for (const auto &bucket : buckets_) { + + search_threads.emplace_back([&] { + auto thread_result = bucket.find_prefix(search_term); + if (!thread_result.empty()) { + std::lock_guard result_lock(result_mutex); + result.merge(thread_result); + } + }); + } + + for (auto &thread : search_threads) { + thread.join(); + } + + return result; +}; diff --git a/vector_search_cli/main.cpp b/vector_search_cli/main.cpp index 117b81f..52a0b2b 100644 --- a/vector_search_cli/main.cpp +++ b/vector_search_cli/main.cpp @@ -1,3 +1,4 @@ +#include "bucket_finder.h" #include "grouped_finder.h" #include "linear_finder.h" #include "parallel_finder.h" @@ -54,6 +55,8 @@ int main(int argc, char *argv[]) { auto word_list = generate_word_list(5); + test_finder(word_list, "bucket finder"); + test_finder(word_list, "linear finder"); test_finder(word_list, "sorted linear finder"); test_finder(word_list, "parallel finder");