From 4029457855d099b4212d94d43d2fb28f1a24644f Mon Sep 17 00:00:00 2001 From: Alexandr Borzykh Date: Tue, 11 Sep 2018 15:07:41 +0300 Subject: [PATCH 1/2] data_structure/dynamic_array: fix forgotten lambda --- include/cslib/data_structure/dynamic_array.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cslib/data_structure/dynamic_array.hpp b/include/cslib/data_structure/dynamic_array.hpp index 29006ea..ee30592 100644 --- a/include/cslib/data_structure/dynamic_array.hpp +++ b/include/cslib/data_structure/dynamic_array.hpp @@ -144,7 +144,7 @@ namespace data_structure : _data(std::allocator_traits::allocate(_allocator, initial_size)), _capacity(initial_size), _size(initial_size) - { algorithm::for_each_iterator(begin(), end(), std::bind(&std::allocator_traits::construct, std::ref(_allocator), std::placeholders::_1, filler)); } + { algorithm::for_each_iterator(begin(), end(), [&](pointer ptr) { std::allocator_traits::construct(_allocator, ptr, filler); }); } template < typename ValueT > From 460bbf7a7803a68735a254260cb20d5cd6bb05f6 Mon Sep 17 00:00:00 2001 From: Alexandr Borzykh Date: Tue, 11 Sep 2018 15:18:00 +0300 Subject: [PATCH 2/2] algorithm/kmp_search: implement generic KMP search --- include/cslib/algorithm/search/kmp_search.hpp | 80 +++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/algorithm/kmp_search.cpp | 25 ++++++ 3 files changed, 106 insertions(+) create mode 100644 include/cslib/algorithm/search/kmp_search.hpp create mode 100644 tests/algorithm/kmp_search.cpp diff --git a/include/cslib/algorithm/search/kmp_search.hpp b/include/cslib/algorithm/search/kmp_search.hpp new file mode 100644 index 0000000..62414c2 --- /dev/null +++ b/include/cslib/algorithm/search/kmp_search.hpp @@ -0,0 +1,80 @@ +#ifndef CSLIB_ALGORITHM_SEARCH_KMP_SEARCH_HPP +#define CSLIB_ALGORITHM_SEARCH_KMP_SEARCH_HPP + +// MIT License +// +// Copyright (c) 2018 Alexandr Borzykh +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include + +#include + +namespace cslib { +namespace algorithm +{ + + /* Name: Knuth-Morris-Pratt searching algorithm + * Runtime complexity: O(n) + * Space complexity: O(m), where m is pattern + * + * Interesting fact: it's widely used with strings, but implementation is generic and can work with basically all containers and types (contained type must have operator==) + */ + + template < typename IteratorT > + IteratorT kmp_search(IteratorT begin, IteratorT end, IteratorT pattern_begin, IteratorT pattern_end) + { + using iterator_traits = std::iterator_traits; + + const typename iterator_traits::difference_type source_length = std::distance(begin, end), pattern_length = std::distance(pattern_begin, pattern_end); + data_structure::dynamic_array prefix_func(pattern_length, 0); + + uint32_t k; + IteratorT pattern_iter; + for (k = 0, pattern_iter = pattern_begin; pattern_iter != pattern_end; ++pattern_iter) + { + while ((k > 0) && (*pattern_iter != *(pattern_begin + k))) + k = prefix_func[k - 1]; + + if (*pattern_iter == *(pattern_begin + k)) + ++k; + + prefix_func[std::distance(pattern_begin, pattern_iter)] = k; + } + + IteratorT source_iter; + for (k = 0, source_iter = begin; source_iter != end; ++source_iter) + { + while ((k > 0) && (*(pattern_begin + k) != *source_iter)) + k = prefix_func[k - 1]; + + if (*(pattern_begin + k) == *source_iter) + ++k; + + if (k == pattern_length) + return source_iter - pattern_length + 1; + } + + return end; + } + +}} + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 45d5be3..21353d5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,7 @@ option(BUILD_TESTS "Build unit tests" OFF) SET(SOURCES algorithm/binary_search.cpp algorithm/linear_search.cpp + algorithm/kmp_search.cpp algorithm/insertion_sort.cpp algorithm/maximum_subarray.cpp diff --git a/tests/algorithm/kmp_search.cpp b/tests/algorithm/kmp_search.cpp new file mode 100644 index 0000000..4c3531d --- /dev/null +++ b/tests/algorithm/kmp_search.cpp @@ -0,0 +1,25 @@ +#include + +#include + +#include + +template +using DefaultContainer = std::vector; + +TEST(kmp_search, empty_input) +{ + DefaultContainer container; + DefaultContainer pattern { 5 }; + + ASSERT_EQ(cslib::algorithm::kmp_search(container.begin(), container.end(), pattern.begin(), pattern.end()), container.end()); +} + + +TEST(kmp_search, simple_input) +{ + DefaultContainer container { 0, 10, 5, 4, 3 }; + DefaultContainer pattern { 5, 4, 3 }; + + ASSERT_EQ(cslib::algorithm::kmp_search(container.begin(), container.end(), pattern.begin(), pattern.end()), container.begin() + 2); +}