cpp09/ex02/PmergeMe.cpp

294 lines
7.1 KiB
C++

#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<int>::const_iterator it = _deq.begin(); it != _deq.end(); ++it)
std::cout << *it << " ";
std::cout << std::endl;
}
void PmergeMe::printVector() const
{
for (std::vector<int>::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<std::pair<int, int> > makePairs(std::vector<int> v)
{
std::vector<std::pair<int, int> > 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<std::pair<int, int> > reorderPairs(std::vector<std::pair<int, int> > pairs, std::vector<int> winners)
{
std::vector<std::pair<int, int> > 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<size_t> generateInsertionOrder(std::vector<int> pend)
{
std::vector<size_t> order;
std::vector<size_t> 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<int> PmergeMe::fordJohnsonVec(std::vector<int> v)
{
if (v.size() <= 1)
return v;
std::vector<std::pair<int, int> > pairs = makePairs(v);
int straggler = 0;
bool hasStraggler = false;
if (v.size() % 2 != 0)
{
straggler = v.back();
hasStraggler = true;
}
std::vector<int> 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<int> mainChain;
mainChain.push_back(pairs[0].second);
for (size_t i = 0; i < pairs.size(); i++)
{
mainChain.push_back(pairs[i].first);
}
std::vector<int> pend;
for (size_t i = 1; i < pairs.size(); i++)
{
pend.push_back(pairs[i].second);
}
std::vector<size_t> 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<int>::iterator aiPos = std::find(mainChain.begin(), mainChain.end(), aiValue);
std::vector<int>::iterator insertPos = std::upper_bound(mainChain.begin(), aiPos, value);
mainChain.insert(insertPos, value);
}
if (hasStraggler)
{
std::vector<int>::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<std::pair<int, int> > makePairs(std::deque<int> d)
{
std::deque<std::pair<int, int> > 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<std::pair<int, int> > reorderPairs(std::deque<std::pair<int, int> > pairs, std::deque<int> winners)
{
std::deque<std::pair<int, int> > 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<size_t> generateInsertionOrder(std::deque<int> pend)
{
std::deque<size_t> order;
std::deque<size_t> 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<int> PmergeMe::fordJohnsonDeque(std::deque<int> d)
{
if (d.size() <= 1)
return d;
std::deque<std::pair<int, int> > pairs = makePairs(d);
int straggler = 0;
bool hasStraggler = false;
if (d.size() % 2 != 0)
{
straggler = d.back();
hasStraggler = true;
}
std::deque<int> 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<int> mainChain;
mainChain.push_back(pairs[0].second);
for (size_t i = 0; i < pairs.size(); i++)
{
mainChain.push_back(pairs[i].first);
}
std::deque<int> pend;
for (size_t i = 1; i < pairs.size(); i++)
{
pend.push_back(pairs[i].second);
}
std::deque<size_t> 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<int>::iterator aiPos = std::find(mainChain.begin(), mainChain.end(), aiValue);
std::deque<int>::iterator insertPos = std::upper_bound(mainChain.begin(), aiPos, value);
mainChain.insert(insertPos, value);
}
if (hasStraggler)
{
std::deque<int>::iterator insertPos = std::upper_bound(mainChain.begin(), mainChain.end(), straggler);
mainChain.insert(insertPos, straggler);
}
return mainChain;
}