From 60050d7b1b0407b54874846fb49d8c2eb9e2b7d6 Mon Sep 17 00:00:00 2001 From: ckontakis <36933662+ckontakis@users.noreply.github.com> Date: Fri, 4 Sep 2020 03:12:56 +0300 Subject: [PATCH] Added Horspool algorithm (#1071) * feat: add Horspool algorithm * Fixed conversion from unsigned long to int with static casting * Removed changes from CMakeLists.txt file * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Documentation, test function and namespaces added * Documentation, test function and namespaces added * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Update strings/horspool.cpp Co-authored-by: David Leal * Removed blank rows * Commit to see if the problem with automated tests is solved Co-authored-by: David Leal --- strings/horspool.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 strings/horspool.cpp diff --git a/strings/horspool.cpp b/strings/horspool.cpp new file mode 100644 index 000000000..a43be5f0d --- /dev/null +++ b/strings/horspool.cpp @@ -0,0 +1,122 @@ +/** + * @file + * @brief Horspool's algorithm that finds if a string contains a substring (https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm) + * @author [Harry Kontakis](https://github.com/ckontakis) + */ + +#include +#include +#include + +/** + * @namespace strings + * @brief Algorithms with strings + */ +namespace strings { +/** + * @namespace horspool + * @brief Functions for [Horspool's](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore%E2%80%93Horspool_algorithm) algorithm + */ +namespace horspool { +/** + * A function that finds the shift table of the given prototype string that we need in Horpool's algorithm. + * @param prototype is the substring that we use to find shift table + * @return Shift Table of Horspool's algorithm + */ +std::unordered_map findShiftTable(const std::string &prototype) { + std::unordered_map + shiftTable; // A HashMap for shift table that has characters for keys and integers for values + + for (int i = 0; i < prototype.size(); + i++) { // Checking all characters of prototype string + if (shiftTable.find(prototype[i]) == + shiftTable.end()) { // If character does not exist in HashMap + if (i != prototype.size() - 1) { + shiftTable.insert(std::make_pair( + prototype[i], prototype.size() - i - + 1)); // Insert the character as key and the size of prototype string - index of character - 1 as value + } else { + shiftTable.insert(std::make_pair( + prototype[i], + prototype.size())); // Insert the character as key and the size of prototype string as value + } + } else { + if (i != prototype.size() - 1) { + shiftTable[prototype[i]] = prototype.size() - i - 1; + } + } + } + return shiftTable; +} + +/** + * A function that implements Horspool's algorithm. + * @param text is the string that we are searching if there is a substring + * @param prototype is the substring that we are searching in text + * @returns true if text string contains prototype string + * @returns false if text string does not contain prototype string + */ +bool horspool(const std::string &text, const std::string &prototype) { + std::unordered_map shiftTable = findShiftTable( + prototype); // Initialise shift table calling findShiftTable function + + int i = static_cast( + prototype.size() - + 1); // Index that we shift in text to find the substring + while (i < text.size()) { + int j = i, k = 0; + bool flag = true; + + for (int z = static_cast(prototype.size() - 1); z >= 0 && flag; + z--) { // Checking if all characters of substring are equal with all characters of string + if (text[j] == prototype[z]) { + k++; + j--; + } else { + flag = false; // If two characters are not equal set flag to false and break from loop + } + } + + if (k == + prototype.size()) { // If all characters match then return true + return true; + } else { + if (shiftTable.find(text[i]) != shiftTable.end()) { + i += shiftTable[text[i]]; // If shift table contains the character then shift index as many steps as value + } else { + i += prototype.size(); // If character does not exist in shift table then shift index as many steps as size of prototype string + } + } + } + return false; +} +} // namespace horspool +} // namespace strings + +/** + * @brief Function with test cases for Horspool's algorithm + * @returns void + */ +static void test(){ + assert(strings::horspool::horspool("Hello World","World") == true); + assert(strings::horspool::horspool("Hello World"," World") == true); + assert(strings::horspool::horspool("Hello World","ello") == true); + assert(strings::horspool::horspool("Hello World","rld") == true); + assert(strings::horspool::horspool("Hello","Helo") == false); + assert(strings::horspool::horspool("c++_algorithms","c++_algorithms") == true); + assert(strings::horspool::horspool("c++_algorithms","c++_") == true); + assert(strings::horspool::horspool("Hello","Hello World") == false); + assert(strings::horspool::horspool("c++_algorithms","") == false); + assert(strings::horspool::horspool("c++","c") == true); + assert(strings::horspool::horspool("3458934793","4793") == true); + assert(strings::horspool::horspool("3458934793","123") == false); +} + +/** + * @brief Main Function that calls test function + * @returns 0 on exit + */ +int main(){ + test(); + return 0; +}