#include "PmergeMe.hpp" PmergeMe::PmergeMe() { } PmergeMe::PmergeMe(const PmergeMe &other) { this->_vec = other._vec; this->_deq = other._deq; } PmergeMe &PmergeMe::operator=(const PmergeMe &other) { this->_vec = other._vec; this->_deq = other._deq; return (*this); } PmergeMe::~PmergeMe() { } void PmergeMe::printDeque() const { for (std::deque::const_iterator it = _deq.begin(); it != _deq.end(); ++it) std::cout << *it << " "; std::cout << std::endl; } void PmergeMe::printVector() const { for (std::vector::const_iterator it = _vec.begin(); it != _vec.end(); ++it) std::cout << *it << " "; std::cout << std::endl; } void PmergeMe::parseInput(int ac, char **av) { std::string token; int n; for (int i = 1; i < ac; i++) { std::istringstream ss(av[i]); while (ss >> token) { std::istringstream iss(token); if (!(iss >> n) || !iss.eof() || n < 0) throw std::runtime_error("Error"); if (std::find(_vec.begin(), _vec.end(), n) != _vec.end()) throw std::runtime_error("Error"); _vec.push_back(n); _deq.push_back(n); } } if (_vec.empty()) throw std::runtime_error("Error"); } void PmergeMe::run(int ac, char **av) { std::cout << std::fixed << std::setprecision(5); parseInput(ac, av); std::cout << "Before: "; printVector(); sortVector(); sortDeque(); std::cout << "After: "; printVector(); std::cout << "Time to process a range of " << _vec.size() << " elements with std::vector : " << _vecTime << " us" << std::endl; std::cout << "Time to process a range of " << _deq.size() << " elements with std::deque : " << _deqTime << " us" << std::endl; } void PmergeMe::sortVector() { clock_t start = clock(); _vec = fordJohnsonVec(_vec); clock_t end = clock(); _vecTime = (double)(end - start) * 1e6 / CLOCKS_PER_SEC; } std::vector > makePairs(std::vector v) { std::vector > pairs; for (size_t i = 0; i + 1 < v.size(); i += 2) { int a = v[i]; int b = v[i + 1]; if (a >= b) pairs.push_back(std::make_pair(a, b)); else pairs.push_back(std::make_pair(b, a)); } return pairs; } std::vector > reorderPairs(std::vector > pairs, std::vector winners) { std::vector > reordered; for (size_t i = 0; i < winners.size(); i++) { for (size_t j = 0; j < pairs.size(); j++) { if (pairs[j].first == winners[i]) { reordered.push_back(pairs[j]); break; } } } return reordered; } std::vector generateInsertionOrder(std::vector pend) { std::vector order; std::vector jacob; jacob.push_back(0); jacob.push_back(1); while (jacob.back() <= pend.size()) jacob.push_back(jacob.back() + 2 * jacob[jacob.size() - 2]); for (size_t k = 3; k < jacob.size(); k++) { size_t high = jacob[k] - 2; if (high >= pend.size()) high = pend.size() - 1; size_t low = jacob[k - 1] - 1; for (size_t idx = high + 1; idx > low; idx--) order.push_back(idx - 1); } return order; } std::vector PmergeMe::fordJohnsonVec(std::vector v) { if (v.size() <= 1) return v; std::vector > pairs = makePairs(v); int straggler = 0; bool hasStraggler = false; if (v.size() % 2 != 0) { straggler = v.back(); hasStraggler = true; } std::vector winners; for (size_t i = 0; i < pairs.size(); i++) winners.push_back(pairs[i].first); winners = fordJohnsonVec(winners); pairs = reorderPairs(pairs, winners); std::vector mainChain; mainChain.push_back(pairs[0].second); for (size_t i = 0; i < pairs.size(); i++) { mainChain.push_back(pairs[i].first); } std::vector pend; for (size_t i = 1; i < pairs.size(); i++) { pend.push_back(pairs[i].second); } std::vector order = generateInsertionOrder(pend); for (size_t i = 0; i < order.size(); i++) { int value = pend[order[i]]; int aiValue = pairs[order[i] + 1].first; std::vector::iterator aiPos = std::find(mainChain.begin(), mainChain.end(), aiValue); std::vector::iterator insertPos = std::upper_bound(mainChain.begin(), aiPos, value); mainChain.insert(insertPos, value); } if (hasStraggler) { std::vector::iterator insertPos = std::upper_bound(mainChain.begin(), mainChain.end(), straggler); mainChain.insert(insertPos, straggler); } return mainChain; } void PmergeMe::sortDeque() { clock_t start = clock(); _deq = fordJohnsonDeque(_deq); clock_t end = clock(); _deqTime = (double)(end - start) * 1e6 / CLOCKS_PER_SEC; } std::deque > makePairs(std::deque d) { std::deque > pairs; for (size_t i = 0; i + 1 < d.size(); i += 2) { int a = d[i]; int b = d[i + 1]; if (a >= b) pairs.push_back(std::make_pair(a, b)); else pairs.push_back(std::make_pair(b, a)); } return pairs; } std::deque > reorderPairs(std::deque > pairs, std::deque winners) { std::deque > reordered; for (size_t i = 0; i < winners.size(); i++) { for (size_t j = 0; j < pairs.size(); j++) { if (pairs[j].first == winners[i]) { reordered.push_back(pairs[j]); break; } } } return reordered; } std::deque generateInsertionOrder(std::deque pend) { std::deque order; std::deque jacob; jacob.push_back(0); jacob.push_back(1); while (jacob.back() <= pend.size()) jacob.push_back(jacob.back() + 2 * jacob[jacob.size() - 2]); for (size_t k = 3; k < jacob.size(); k++) { size_t high = jacob[k] - 2; if (high >= pend.size()) high = pend.size() - 1; size_t low = jacob[k - 1] - 1; for (size_t idx = high + 1; idx > low; idx--) order.push_back(idx - 1); } return order; } std::deque PmergeMe::fordJohnsonDeque(std::deque d) { if (d.size() <= 1) return d; std::deque > pairs = makePairs(d); int straggler = 0; bool hasStraggler = false; if (d.size() % 2 != 0) { straggler = d.back(); hasStraggler = true; } std::deque winners; for (size_t i = 0; i < pairs.size(); i++) winners.push_back(pairs[i].first); winners = fordJohnsonDeque(winners); pairs = reorderPairs(pairs, winners); std::deque mainChain; mainChain.push_back(pairs[0].second); for (size_t i = 0; i < pairs.size(); i++) { mainChain.push_back(pairs[i].first); } std::deque pend; for (size_t i = 1; i < pairs.size(); i++) { pend.push_back(pairs[i].second); } std::deque order = generateInsertionOrder(pend); for (size_t i = 0; i < order.size(); i++) { int value = pend[order[i]]; int aiValue = pairs[order[i] + 1].first; std::deque::iterator aiPos = std::find(mainChain.begin(), mainChain.end(), aiValue); std::deque::iterator insertPos = std::upper_bound(mainChain.begin(), aiPos, value); mainChain.insert(insertPos, value); } if (hasStraggler) { std::deque::iterator insertPos = std::upper_bound(mainChain.begin(), mainChain.end(), straggler); mainChain.insert(insertPos, straggler); } return mainChain; }