From e696e2a994a7d013f3fb0cbad6c2e65130c60104 Mon Sep 17 00:00:00 2001 From: whaffman Date: Thu, 4 Sep 2025 16:18:25 +0200 Subject: [PATCH] Refactor PmergeMe class; implement template-based sorting and insertion methods, enhance timing output, and update VSCode settings --- .vscode/settings.json | 3 +- ex02/inc/PmergeMe.hpp | 13 ++-- ex02/inc/PmergeMe.tpp | 85 ++++++++++++++++++++++++++ ex02/src/PmergeMe.cpp | 139 ++++++------------------------------------ ex02/src/main.cpp | 4 +- 5 files changed, 116 insertions(+), 128 deletions(-) create mode 100644 ex02/inc/PmergeMe.tpp diff --git a/.vscode/settings.json b/.vscode/settings.json index 271dbab..51a1ca9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,6 +50,7 @@ "typeinfo": "cpp", "ctime": "cpp", "iomanip": "cpp", - "sstream": "cpp" + "sstream": "cpp", + "*.tpp": "cpp" } } \ No newline at end of file diff --git a/ex02/inc/PmergeMe.hpp b/ex02/inc/PmergeMe.hpp index 9e1b3f8..89d657b 100644 --- a/ex02/inc/PmergeMe.hpp +++ b/ex02/inc/PmergeMe.hpp @@ -14,10 +14,8 @@ public: ~PmergeMe(); PmergeMe &operator=(const PmergeMe &other); - std::ostream &operator<<(std::ostream &os) const; void sort(); - void sortVector(int level); std::string getPrintableVector() const; std::string getPrintableDeque() const; @@ -29,7 +27,14 @@ private: int _comparisons; bool areAllUnique() const; - void insertVector(std::vector &main, std::vector &pend, int start_index, int right, int group_size); + + template + void insert(Container &main, Container &pend, int start_index, int right, int group_size); + + template + Container sort(Container &data, int level); }; -std::ostream &operator<<(std::ostream &os, const PmergeMe &obj); \ No newline at end of file +std::ostream &operator<<(std::ostream &os, const PmergeMe &obj); + +#include "PmergeMe.tpp" \ No newline at end of file diff --git a/ex02/inc/PmergeMe.tpp b/ex02/inc/PmergeMe.tpp new file mode 100644 index 0000000..965ef98 --- /dev/null +++ b/ex02/inc/PmergeMe.tpp @@ -0,0 +1,85 @@ +#include "PmergeMe.hpp" + +template +Container PmergeMe::sort(Container &data, int level) +{ + // #1 Create pairs and sort them + if (data.size() <= 1) + return data; + + size_t group_size = 1 << level; + + int odd = data.size() % (2 * group_size); + + Container straggler = Container(data.end() - odd, data.end()); + + data.erase(data.end() - odd, data.end()); + + for (size_t i = 0; i < data.size(); i += (2 * group_size)) + { + if (!less(data[i + group_size - 1], data[i + 2 * group_size - 1])) + std::swap_ranges( + data.begin() + i, data.begin() + i + group_size, + data.begin() + i + group_size); + } + + if (2 * group_size < data.size()) + data = sort(data, level + 1); + + Container main; + Container pend; + + // #3 Separate main and pend + main.insert(main.end(), data.begin(), data.begin() + group_size); // inserting b1 + auto it = data.begin() + group_size; // this is a1 + while (it != data.end()) + { + main.insert(main.end(), it, it + group_size); + it += group_size; + if (it == data.end()) + break; + pend.insert(pend.end(), it, it + group_size); + it += group_size; + } + pend.insert(pend.end(), straggler.begin(), straggler.end()); + + int i = 0; + while (!pend.empty()) + { + int search_window = std::min((1 << (i + 2)) - 1, static_cast(main.size() / group_size)); + + int jacob_index = Jacobstahl().get(i + 3) - Jacobstahl().get(i + 2) - 1; + int first_to_insert = std::min(jacob_index, static_cast(pend.size() / group_size) - 1); + + for (int to_insert = first_to_insert; to_insert >= 0; --to_insert) + insert(main, pend, to_insert, search_window, group_size); + + i++; + } + return main; +} + +template +void PmergeMe::insert(Container &main, Container &pend, int to_insert, int right, int group_size) +{ + if (pend.empty() || to_insert < 0 || to_insert >= static_cast(pend.size())) + return; + + int value_to_insert = pend[(to_insert + 1) * group_size - 1]; + auto insert_pos = main.begin() + right * group_size; + + int left = 0; + while (left < right) + { + int mid = left + (right - left) / 2; + int last_idx = std::min((mid + 1) * group_size, static_cast(main.size())) - 1; + if (less(main[last_idx], value_to_insert)) + left = mid + 1; + else + right = mid; + } + insert_pos = main.begin() + (left * group_size); + + main.insert(insert_pos, pend.begin() + to_insert * group_size, pend.begin() + (to_insert + 1) * group_size); + pend.erase(pend.begin() + to_insert * group_size, pend.begin() + (to_insert + 1) * group_size); +} \ No newline at end of file diff --git a/ex02/src/PmergeMe.cpp b/ex02/src/PmergeMe.cpp index bff03c1..d44d6d2 100644 --- a/ex02/src/PmergeMe.cpp +++ b/ex02/src/PmergeMe.cpp @@ -8,6 +8,7 @@ #include #include #include +#include std::ostream &operator<<(std::ostream &os, const std::vector &obj) { @@ -63,96 +64,28 @@ PmergeMe &PmergeMe::operator=(const PmergeMe &other) return *this; } -std::ostream &PmergeMe::operator<<(std::ostream &os) const -{ - os << "Vector: "; - for (std::vector::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it) - { - if (it != _data_vector.begin()) - os << " "; - os << *it; - } - os << "\nDeque: "; - for (std::deque::const_iterator it = _data_deque.begin(); it != _data_deque.end(); ++it) - { - if (it != _data_deque.begin()) - os << " "; - os << *it; - } - return os; -} - void PmergeMe::sort() { + + //high resolution timing _comparisons = 0; - sortVector(0); - std::cout << "Total comparisons: " << _comparisons << std::endl; - std::cout << (std::is_sorted(_data_vector.begin(), _data_vector.end()) ? "Sorted!!!" : "ERROR!!") << std::endl; - std::sort(_data_deque.begin(), _data_deque.end()); -} + auto time_start = std::chrono::high_resolution_clock::now(); + _data_vector = sort(_data_vector, 0); + // std::cout << "Total comparisons: " << _comparisons << std::endl; + // std::cout << (std::is_sorted(_data_vector.begin(), _data_vector.end()) ? "Sorted!!!" : "ERROR!!") << std::endl; + auto time_end = std::chrono::high_resolution_clock::now(); + auto time_diff = std::chrono::duration_cast(time_end - time_start).count(); + std::cout << "Time to process a range of " << _data_vector.size() << " elements with std::vector : " << time_diff << " us" << std::endl; -void PmergeMe::sortVector(int level = 0) -{ - // #1 Create pairs and sort them - if (_data_vector.size() <= 1) - return; + _comparisons = 0; + auto time_start_deque = std::chrono::high_resolution_clock::now(); + _data_deque = sort(_data_deque, 0); + // std::cout << "Total comparisons: " << _comparisons << std::endl; + // std::cout << (std::is_sorted(_data_deque.begin(), _data_deque.end()) ? "Sorted!!!" : "ERROR!!") << std::endl; + auto time_end_deque = std::chrono::high_resolution_clock::now(); + auto time_diff_deque = std::chrono::duration_cast(time_end_deque - time_start_deque).count(); + std::cout << "Time to process a range of " << _data_deque.size() << " elements with std::deque : " << time_diff_deque << " us" << std::endl; - size_t group_size = std::pow(2, level + 1); - - int odd = _data_vector.size() % group_size; - - std::vector left = std::vector(_data_vector.end() - odd, _data_vector.end()); - - _data_vector.erase(_data_vector.end() - odd, _data_vector.end()); - - for (size_t i = 0; i < _data_vector.size(); i += group_size) - { - if (!less(_data_vector[i + group_size / 2 - 1], _data_vector[i + group_size - 1])) - std::swap_ranges( - _data_vector.begin() + i, _data_vector.begin() + i + group_size / 2, - _data_vector.begin() + i + group_size / 2); - } - - if (group_size < _data_vector.size()) - sortVector(level + 1); - - std::vector main; - std::vector pend; - - // #3 Separate main and pend - group_size /= 2; - main.insert(main.end(), _data_vector.begin(), _data_vector.begin() + group_size); // inserting b1 - auto it = _data_vector.begin() + group_size; // this is a1 - while (it != _data_vector.end()) - { - main.insert(main.end(), it, it + group_size); - it += group_size; - if (it == _data_vector.end()) - break; - pend.insert(pend.end(), it, it + group_size); - it += group_size; - } - pend.insert(pend.end(), left.begin(), left.end()); - - int i = 0; - while (!pend.empty()) - { - int sorted_in_main = std::pow(2, i + 2) - 1; // TODO ?? - sorted_in_main = sorted_in_main > static_cast(main.size() / group_size) - ? static_cast(main.size() / group_size) - : sorted_in_main; - - int jacob_index = Jacobstahl().get(i + 3) - Jacobstahl().get(i + 2) - 1; - int start_index = std::min(jacob_index, static_cast(pend.size() / group_size) - 1); - - for (int j = start_index; j >= 0; --j) - { - insertVector(main, pend, j, sorted_in_main, group_size); - } - - i++; - } - _data_vector = main; } std::string PmergeMe::getPrintableVector() const @@ -193,42 +126,6 @@ bool PmergeMe::areAllUnique() const return it == temp.end(); } -void PmergeMe::insertVector(std::vector &main, std::vector &pend, int start_index, int right, int group_size) -{ - if (pend.empty() || start_index < 0 || start_index >= static_cast(pend.size())) - return; - - // Use the last element in the group for binary search - int value_to_insert = pend[(start_index + 1) * group_size - 1]; - - std::cout - // << main << " | " << std::setw(3) << value_to_insert << " | " << pend << " | pend_index: " << start_index - << " | main: " << main.size() / group_size << " | end: " << right << " | group_size: " << group_size - << (!std::is_sorted(main.begin(), main.end()) && group_size == 1 ? "<<<" : "") << std::endl; - - auto insert_pos = main.begin() + right * group_size; - int left = 0; - - while (left < right) - { - int mid = left + (right - left) / 2; - int last_idx = std::min((mid + 1) * group_size, static_cast(main.size())) - 1; - if (less(main[last_idx], value_to_insert)) - { - left = mid + 1; - } - else - { - right = mid; - } - } - insert_pos = main.begin() + (left * group_size); - - main.insert(insert_pos, pend.begin() + start_index * group_size, pend.begin() + (start_index + 1) * group_size); - - pend.erase(pend.begin() + start_index * group_size, pend.begin() + (start_index + 1) * group_size); -} - std::ostream &operator<<(std::ostream &os, const PmergeMe &obj) { os << "Vector: " << obj.getPrintableVector() << "\n"; diff --git a/ex02/src/main.cpp b/ex02/src/main.cpp index 39ae9fa..b276b28 100644 --- a/ex02/src/main.cpp +++ b/ex02/src/main.cpp @@ -8,9 +8,9 @@ int main(const int argc, const char **argv) try { PmergeMe sorter(argc, argv); - // std::cout << "Before sorting:\n" << sorter << std::endl; + std::cout << "Before sorting:\n" << sorter << std::endl; sorter.sort(); - // std::cout << "After sorting:\n" << sorter << std::endl; + std::cout << "After sorting:\n" << sorter << std::endl; } catch (const std::invalid_argument &e) {