diff --git a/include/etl/algorithm.h b/include/etl/algorithm.h index cb7b5b19..fe638dc0 100644 --- a/include/etl/algorithm.h +++ b/include/etl/algorithm.h @@ -1143,6 +1143,53 @@ namespace etl } } + //*************************************************************************** + /// partial_sort + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + void partial_sort(TIterator first, TIterator middle, TIterator last, TCompare compare) + { + if (first == middle) + { + return; + } + + typedef typename etl::iterator_traits::value_type value_t; + typedef typename etl::iterator_traits::difference_type difference_t; + + etl::make_heap(first, middle, compare); + + for (TIterator i = middle; i != last; ++i) + { + if (compare(*i, *first)) + { + value_t value = ETL_MOVE(*i); + *i = ETL_MOVE(*first); + + private_heap::adjust_heap(first, difference_t(0), difference_t(middle - first), ETL_MOVE(value), compare); + } + } + + etl::sort_heap(first, middle, compare); + } + + //*************************************************************************** + /// partial_sort + ///\ingroup algorithm + /// + //*************************************************************************** + template + ETL_CONSTEXPR14 + void partial_sort(TIterator first, TIterator middle, TIterator last) + { + typedef etl::less::value_type> compare; + + etl::partial_sort(first, middle, last, compare()); + } + //*************************************************************************** // Search //*************************************************************************** diff --git a/test/test_algorithm.cpp b/test/test_algorithm.cpp index e750e3f3..6610e0d9 100644 --- a/test/test_algorithm.cpp +++ b/test/test_algorithm.cpp @@ -1744,6 +1744,195 @@ namespace CHECK(isEqual); } + //************************************************************************* + TEST(partial_sort_default) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + // The first 5 elements should be sorted and match std + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + // Verify sorted range + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_compare) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end(), Greater()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end(), Greater()); + + // The first 5 elements should be sorted descending and match std + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + // Verify sorted range (descending) + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5, Greater())); + } + + //************************************************************************* + TEST(partial_sort_empty) + { + std::vector data; + + etl::partial_sort(data.begin(), data.begin(), data.end()); + + CHECK(data.empty()); + } + + //************************************************************************* + TEST(partial_sort_middle_equals_first) + { + std::vector data = { 5, 3, 8, 1, 9 }; + std::vector original(data); + + etl::partial_sort(data.begin(), data.begin(), data.end()); + + // Nothing should change when middle == first + bool isEqual = std::equal(data.begin(), data.end(), original.begin()); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_middle_equals_last) + { + std::vector data1 = { 5, 3, 8, 1, 9 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.end(), data1.end()); + etl::partial_sort(data2.begin(), data2.end(), data2.end()); + + // Full sort + bool isEqual = std::equal(data1.begin(), data1.end(), data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.end())); + } + + //************************************************************************* + TEST(partial_sort_single_element) + { + std::vector data = { 42 }; + + etl::partial_sort(data.begin(), data.end(), data.end()); + + CHECK_EQUAL(1U, data.size()); + CHECK_EQUAL(42, data[0]); + } + + //************************************************************************* + TEST(partial_sort_first_one) + { + std::vector data1 = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 1, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 1, data2.end()); + + // The first element should be the minimum + CHECK_EQUAL(data1[0], data2[0]); + CHECK_EQUAL(1, data2[0]); + } + + //************************************************************************* + TEST(partial_sort_duplicates) + { + std::vector data1 = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 6, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 6, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 6, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 6)); + } + + //************************************************************************* + TEST(partial_sort_already_sorted) + { + std::vector data1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_reverse_sorted) + { + std::vector data1 = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; + std::vector data2(data1); + + std::partial_sort(data1.begin(), data1.begin() + 5, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 5, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 5, data2.begin()); + CHECK(isEqual); + + CHECK(std::is_sorted(data2.begin(), data2.begin() + 5)); + } + + //************************************************************************* + TEST(partial_sort_pointer) + { + int data1[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + int data2[] = { 5, 3, 8, 1, 9, 2, 7, 4, 6, 10 }; + + std::partial_sort(std::begin(data1), std::begin(data1) + 5, std::end(data1)); + etl::partial_sort(std::begin(data2), std::begin(data2) + 5, std::end(data2)); + + bool isEqual = std::equal(std::begin(data1), std::begin(data1) + 5, std::begin(data2)); + CHECK(isEqual); + } + + //************************************************************************* + TEST(partial_sort_all_permutations) + { + std::vector initial = { 1, 2, 3, 4, 5 }; + + do + { + std::vector data1(initial); + std::vector data2(initial); + + std::partial_sort(data1.begin(), data1.begin() + 3, data1.end()); + etl::partial_sort(data2.begin(), data2.begin() + 3, data2.end()); + + bool isEqual = std::equal(data1.begin(), data1.begin() + 3, data2.begin()); + CHECK(isEqual); + } while (std::next_permutation(initial.begin(), initial.end())); + } + + //************************************************************************* + TEST(partial_sort_all_equal) + { + std::vector data = { 5, 5, 5, 5, 5, 5 }; + + etl::partial_sort(data.begin(), data.begin() + 3, data.end()); + + CHECK(std::is_sorted(data.begin(), data.begin() + 3)); + + for (size_t i = 0; i < data.size(); ++i) + { + CHECK_EQUAL(5, data[i]); + } + } + //************************************************************************* TEST(find) {