diff --git a/ex02/Makefile b/ex02/Makefile new file mode 100644 index 0000000..4f0c558 --- /dev/null +++ b/ex02/Makefile @@ -0,0 +1,4 @@ +override NAME = PmergeMe +override SRC_FILES = main.cpp PmergeMe.cpp + +include ../Makefile diff --git a/ex02/src/PmergeMe.cpp b/ex02/src/PmergeMe.cpp new file mode 100644 index 0000000..d8db54b --- /dev/null +++ b/ex02/src/PmergeMe.cpp @@ -0,0 +1,129 @@ +#include + +#include +#include +#include +#include +#include +#include + +PmergeMe::PmergeMe() {} + +PmergeMe::PmergeMe(const PmergeMe& other) { + (void)other; // yeag... +} + +static std::vector generateJacobsthal(const size_t n) { + std::vector jacobsthal; + + jacobsthal.push_back(0); + jacobsthal.push_back(1); + while (jacobsthal.back() < n) { + const size_t next = jacobsthal[jacobsthal.size() - 1] + 2 * jacobsthal[jacobsthal.size() - 2]; + jacobsthal.push_back(next); + } + + return jacobsthal; +} + +template Container fordJohnsonSortRange(const Container& input) { + typedef typename Container::value_type ValueType; + typedef std::pair PairType; + + const size_t size = input.size(); + if (size <= 1) + return input; + + std::vector pairs; + for (size_t i = 0; i + 1 < size; i += 2) { + if (input[i] <= input[i + 1]) { + pairs.push_back(std::make_pair(input[i], input[i + 1])); + } else { + pairs.push_back(std::make_pair(input[i + 1], input[i])); + } + } + + Container largerElements; + for (size_t i = 0; i < pairs.size(); ++i) + largerElements.push_back(pairs[i].second); + + largerElements = fordJohnsonSortRange(largerElements); + + if (pairs.empty()) + return largerElements; + + const typename Container::iterator firstUpper = std::upper_bound(largerElements.begin(), largerElements.end(), pairs[0].second); + const typename Container::iterator firstPosition = std::upper_bound(largerElements.begin(), firstUpper, pairs[0].first); + largerElements.insert(firstPosition, pairs[0].first); + + const std::vector jacobsthal = generateJacobsthal(pairs.size()); + for (size_t i = 3; i < jacobsthal.size() && jacobsthal[i - 1] < pairs.size(); ++i) { + const size_t start = jacobsthal[i - 1]; + const size_t end = std::min(jacobsthal[i] - 1, pairs.size() - 1); + + for (size_t idx = end; idx >= start; --idx) { + const typename Container::iterator upper = std::upper_bound(largerElements.begin(), largerElements.end(), pairs[idx].second); + const typename Container::iterator position = std::upper_bound(largerElements.begin(), upper, pairs[idx].first); + largerElements.insert(position, pairs[idx].first); + } + } + + if (size % 2 == 1) { + const typename Container::iterator position = std::upper_bound(largerElements.begin(), largerElements.end(), input[size - 1]); + largerElements.insert(position, input[size - 1]); + } + + return largerElements; +} +template void fordJohnsonSort(Container& container) { container = fordJohnsonSortRange(container); } + +template std::vector fordJohnsonSortRange >(const std::vector&); +template std::deque fordJohnsonSortRange >(const std::deque&); + +template void fordJohnsonSort >(std::vector&); +template void fordJohnsonSort >(std::deque&); + +static double elapsedMicroseconds(const timespec& start, const timespec& end) { return (static_cast(end.tv_sec - start.tv_sec) * 1000000 + static_cast(end.tv_nsec - start.tv_nsec)) / 1000; } + +static std::ostream& operator<<(std::ostream& stream, const std::vector& vector) { + for (size_t i = 0; i < vector.size(); ++i) { + stream << vector[i]; + if (i + 1 < vector.size()) + stream << " "; + } + + return stream; +} + +void PmergeMe::sort(std::vector& vector, std::deque& deque) { + { + std::cout << "Before: " << vector << std::endl; + timespec start, end; + + clock_gettime(CLOCK_MONOTONIC, &start); + fordJohnsonSort(vector); + clock_gettime(CLOCK_MONOTONIC, &end); + + std::cout << "After: " << vector << std::endl; + std::cout << "Time to process a range of " << vector.size() << " elements with std::vector : " << elapsedMicroseconds(start, end) << " us" << std::endl; + } + + { + timespec start, end; + + clock_gettime(CLOCK_MONOTONIC, &start); + fordJohnsonSort(deque); + clock_gettime(CLOCK_MONOTONIC, &end); + + std::cout << "Time to process a range of " << deque.size() << " elements with std::deque : " << elapsedMicroseconds(start, end) << " us" << std::endl; + } +} + +PmergeMe& PmergeMe::operator=(const PmergeMe& other) { + if (this == &other) + return *this; + + return *this; +} + +PmergeMe::~PmergeMe() {} diff --git a/ex02/src/PmergeMe.hpp b/ex02/src/PmergeMe.hpp new file mode 100644 index 0000000..8284597 --- /dev/null +++ b/ex02/src/PmergeMe.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +class PmergeMe { + public: + PmergeMe(); + PmergeMe(const PmergeMe& other); + + static void sort(std::vector& vector, std::deque& deque); + + PmergeMe& operator=(const PmergeMe& other); + + ~PmergeMe(); +}; diff --git a/ex02/src/main.cpp b/ex02/src/main.cpp new file mode 100644 index 0000000..d8631d6 --- /dev/null +++ b/ex02/src/main.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + return 1; + } + + std::cout << std::fixed << std::setprecision(5); + + std::vector vector; + try { + if (argc == 2) { + std::string input = argv[1]; + std::istringstream inputStream(input); + std::string string; + while (inputStream >> string) { + for (size_t i = 0; i < string.size(); ++i) + if (!std::isdigit(static_cast(string[i]))) + throw std::runtime_error("Error: not a number"); + + long number = std::strtol(string.c_str(), NULL, 10); + + if (number < 0) + throw std::runtime_error("Error: negative number"); + + if (number > std::numeric_limits::max()) + throw std::runtime_error("Error: too large"); + + vector.push_back(static_cast(number)); + } + } else { + for (int i = 1; i < argc; ++i) { + for (size_t j = 0; argv[i][j] != '\0'; ++j) + if (!std::isdigit(static_cast(argv[i][j]))) + throw std::runtime_error("Error: not a number"); + + long int number = std::strtol(argv[i], NULL, 10); + + if (number < 0) + throw std::runtime_error("Error: negative number"); + + if (number > std::numeric_limits::max()) + throw std::runtime_error("Error: too large"); + + vector.push_back(static_cast(number)); + } + } + } catch (const std::exception& exception) { + std::cerr << exception.what() << std::endl; + return EXIT_FAILURE; + } + std::deque deque(vector.begin(), vector.end()); + + PmergeMe::sort(vector, deque); +}