Refactor PmergeMe class; reorganize includes, improve formatting, and streamline constructor logic

off by one error in binary search
This commit is contained in:
whaffman 2025-09-03 22:35:36 +02:00
parent 1370dab089
commit bfbbb4acdd

View File

@ -1,242 +1,237 @@
#include "PmergeMe.hpp" #include "PmergeMe.hpp"
#include <algorithm> #include <algorithm>
#include <vector> #include <cmath>
#include <cstring>
#include <deque> #include <deque>
#include <string> #include <iomanip>
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <cstring> #include <string>
#include <cmath> #include <vector>
#include <ostream>
#include <iomanip>
std::ostream &operator<<(std::ostream &os, const std::vector<int> &obj) std::ostream &operator<<(std::ostream &os, const std::vector<int> &obj)
{ {
for (std::vector<int>::const_iterator it = obj.begin(); it != obj.end(); ++it) for (std::vector<int>::const_iterator it = obj.begin(); it != obj.end(); ++it)
{ {
if (it != obj.begin()) if (it != obj.begin())
os << " "; os << " ";
os << *it; os << *it;
} }
return os; return os;
} }
PmergeMe::PmergeMe(const int argc, const char **argv) : _comparisons(0) PmergeMe::PmergeMe(const int argc, const char **argv) : _comparisons(0)
{ {
for (int i = 1; argv[i] != nullptr; ++i) for (int i = 1; argv[i] != nullptr; ++i)
{ {
size_t pos; size_t pos;
int value = std::stoi(argv[i], &pos); int value = std::stoi(argv[i], &pos);
if (value < 0) if (value < 0)
throw std::invalid_argument("All inputs must be non-negative integers"); throw std::invalid_argument("All inputs must be non-negative integers");
if (pos != std::strlen(argv[i])) if (pos != std::strlen(argv[i]))
throw std::invalid_argument("Invalid input: not a valid integer"); throw std::invalid_argument("Invalid input: not a valid integer");
_data_vector.push_back(value); _data_vector.push_back(value);
_data_deque.push_back(value); _data_deque.push_back(value);
} }
if (!areAllUnique()) if (!areAllUnique())
throw std::invalid_argument("All inputs must be unique integers"); throw std::invalid_argument("All inputs must be unique integers");
if (_data_vector.size() != static_cast<std::size_t>(argc) - 1 || _data_deque.size() != static_cast<std::size_t>(argc) - 1) if (_data_vector.size() != static_cast<std::size_t>(argc) - 1
throw std::invalid_argument("Invalid input detected"); || _data_deque.size() != static_cast<std::size_t>(argc) - 1)
throw std::invalid_argument("Invalid input detected");
_jacobstahl_numbers = Jacobstahl().getUpTo(_data_vector.size()); _jacobstahl_numbers = Jacobstahl().getUpTo(_data_vector.size());
} }
PmergeMe::PmergeMe(const PmergeMe &other) PmergeMe::PmergeMe(const PmergeMe &other)
: _data_vector(other._data_vector), _data_deque(other._data_deque), _jacobstahl_numbers(other._jacobstahl_numbers) : _data_vector(other._data_vector), _data_deque(other._data_deque), _jacobstahl_numbers(other._jacobstahl_numbers)
{ {}
}
PmergeMe::~PmergeMe() PmergeMe::~PmergeMe() {}
{
}
PmergeMe &PmergeMe::operator=(const PmergeMe &other) PmergeMe &PmergeMe::operator=(const PmergeMe &other)
{ {
if (this != &other) if (this != &other)
{ {
_data_vector = other._data_vector; _data_vector = other._data_vector;
_data_deque = other._data_deque; _data_deque = other._data_deque;
_jacobstahl_numbers = other._jacobstahl_numbers; _jacobstahl_numbers = other._jacobstahl_numbers;
} }
return *this; return *this;
} }
std::ostream &PmergeMe::operator<<(std::ostream &os) const std::ostream &PmergeMe::operator<<(std::ostream &os) const
{ {
os << "Vector: "; os << "Vector: ";
for (std::vector<int>::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it) for (std::vector<int>::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it)
{ {
if (it != _data_vector.begin()) if (it != _data_vector.begin())
os << " "; os << " ";
os << *it; os << *it;
} }
os << "\nDeque: "; os << "\nDeque: ";
for (std::deque<int>::const_iterator it = _data_deque.begin(); it != _data_deque.end(); ++it) for (std::deque<int>::const_iterator it = _data_deque.begin(); it != _data_deque.end(); ++it)
{ {
if (it != _data_deque.begin()) if (it != _data_deque.begin())
os << " "; os << " ";
os << *it; os << *it;
} }
return os; return os;
} }
void PmergeMe::sort() void PmergeMe::sort()
{ {
_comparisons = 0; _comparisons = 0;
sortVector(0); sortVector(0);
std::cout << "Total comparisons: " << _comparisons << std::endl; std::cout << "Total comparisons: " << _comparisons << std::endl;
std::cout << (std::is_sorted(_data_vector.begin(), _data_vector.end()) ? "Sorted!!!" : "ERROR!!") << 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()); std::sort(_data_deque.begin(), _data_deque.end());
} }
void PmergeMe::sortVector(int level = 0) void PmergeMe::sortVector(int level = 0)
{ {
// #1 Create pairs and sort them // #1 Create pairs and sort them
if (_data_vector.size() <= 1) if (_data_vector.size() <= 1)
return; return;
size_t group_size = std::pow(2, level + 1); size_t group_size = std::pow(2, level + 1);
int odd = _data_vector.size() % group_size; int odd = _data_vector.size() % group_size;
std::vector<int> left = std::vector<int>(_data_vector.end() - odd, _data_vector.end()); std::vector<int> left = std::vector<int>(_data_vector.end() - odd, _data_vector.end());
_data_vector.erase(_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) 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])) 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); 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()) if (group_size < _data_vector.size())
sortVector(level + 1); sortVector(level + 1);
std::vector<int> main; std::vector<int> main;
std::vector<int> pend; std::vector<int> pend;
// #3 Separate main and pend // #3 Separate main and pend
group_size /= 2; group_size /= 2;
main.insert(main.end(), _data_vector.begin(), _data_vector.begin() + group_size); // inserting b1 main.insert(main.end(), _data_vector.begin(), _data_vector.begin() + group_size); // inserting b1
auto it = _data_vector.begin() + group_size; // this is a1 auto it = _data_vector.begin() + group_size; // this is a1
while (it != _data_vector.end()) while (it != _data_vector.end())
{ {
// if (it + group_size > _data_vector.end()) main.insert(main.end(), it, it + group_size);
// group_size = _data_vector.end() - it; it += group_size;
main.insert(main.end(), it, it + group_size); if (it == _data_vector.end())
it += group_size; break;
if (it == _data_vector.end()) pend.insert(pend.end(), it, it + group_size);
break; it += group_size;
// if (it + group_size > _data_vector.end()) }
// group_size = _data_vector.end() - it; pend.insert(pend.end(), left.begin(), left.end());
pend.insert(pend.end(), it, it + group_size);
it += group_size;
}
pend.insert(pend.end(), left.begin(), left.end());
int i = 0; int i = 0;
while (!pend.empty()) while (!pend.empty())
{ {
int sorted_in_main = std::pow(2, i + 2) -1 ; // TODO ?? int sorted_in_main = std::pow(2, i + 2) - 1; // TODO ??
sorted_in_main = sorted_in_main > static_cast<int>(main.size() / group_size) ? static_cast<int>(main.size() / group_size) : sorted_in_main; sorted_in_main = sorted_in_main > static_cast<int>(main.size() / group_size)
? static_cast<int>(main.size() / group_size)
: sorted_in_main;
int jacob_index = Jacobstahl().get(i + 3) - Jacobstahl().get(i + 2) - 1; int jacob_index = Jacobstahl().get(i + 3) - Jacobstahl().get(i + 2) - 1;
int start_index = std::min(jacob_index, static_cast<int>(pend.size() / group_size) - 1); int start_index = std::min(jacob_index, static_cast<int>(pend.size() / group_size) - 1);
for (int j = start_index; j >= 0; --j) for (int j = start_index; j >= 0; --j)
{ {
insertVector(main, pend, j, sorted_in_main, group_size);
}
insertVector(main, pend, j, sorted_in_main, group_size); i++;
// std::cout << "insertVector(main, pend, " << j << ", " << sorted_in_main << ", " << group_size << ")" << std::endl; }
// sorted_in_main--; _data_vector = main;
}
i++;
}
_data_vector = main;
} }
std::string PmergeMe::getPrintableVector() const std::string PmergeMe::getPrintableVector() const
{ {
std::string result; std::string result;
for (std::vector<int>::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it) for (std::vector<int>::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it)
{ {
if (it != _data_vector.begin()) if (it != _data_vector.begin())
result += ", "; result += ", ";
result += std::to_string(*it); result += std::to_string(*it);
} }
return result; return result;
} }
std::string PmergeMe::getPrintableDeque() const std::string PmergeMe::getPrintableDeque() const
{ {
std::string result; std::string result;
for (std::deque<int>::const_iterator it = _data_deque.begin(); it != _data_deque.end(); ++it) for (std::deque<int>::const_iterator it = _data_deque.begin(); it != _data_deque.end(); ++it)
{ {
if (it != _data_deque.begin()) if (it != _data_deque.begin())
result += ", "; result += ", ";
result += std::to_string(*it); result += std::to_string(*it);
} }
return result; return result;
} }
bool PmergeMe::less(int a, int b) bool PmergeMe::less(int a, int b)
{ {
_comparisons++; _comparisons++;
return a < b; return a < b;
} }
bool PmergeMe::areAllUnique() const bool PmergeMe::areAllUnique() const
{ {
std::vector<int> temp = _data_vector; // Create a copy std::vector<int> temp = _data_vector; // Create a copy
std::sort(temp.begin(), temp.end()); std::sort(temp.begin(), temp.end());
auto it = std::unique(temp.begin(), temp.end()); auto it = std::unique(temp.begin(), temp.end());
return it == temp.end(); return it == temp.end();
} }
void PmergeMe::insertVector(std::vector<int> &main, std::vector<int> &pend, int start_index, int right, int group_size) void PmergeMe::insertVector(std::vector<int> &main, std::vector<int> &pend, int start_index, int right, int group_size)
{ {
if (pend.empty() || start_index < 0 || start_index >= static_cast<int>(pend.size())) if (pend.empty() || start_index < 0 || start_index >= static_cast<int>(pend.size()))
return; return;
// Use the last element in the group for binary search // Use the last element in the group for binary search
int value_to_insert = pend[(start_index + 1) * group_size - 1]; int value_to_insert = pend[(start_index + 1) * group_size - 1];
// std::cout << "Value to insert: " << value_to_insert << std::endl;
// std::cout << main << " | " << std::setw(3) << value_to_insert << " | " << pend
// << " | start_index: " << start_index << " | right: " << 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; std::cout
int left = 0; // << 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;
while (left <= right) auto insert_pos = main.begin() + right * group_size;
{ int left = 0;
int mid = left + (right - left) / 2;
int last_idx = std::min((mid + 1) * group_size, static_cast<int>(main.size())) - 1;
if (less(main[last_idx], value_to_insert))
{
left = mid + 1;
}
else
{
right = mid - 1;
insert_pos = main.begin() + (mid * group_size); // Insert before the start of the found group //TODO ??
}
}
main.insert(insert_pos, pend.begin() + start_index * group_size, pend.begin() + (start_index + 1) * group_size); while (left < right)
// std::cout << "After insertion: " << main << std::endl; {
int mid = left + (right - left) / 2;
int last_idx = std::min((mid + 1) * group_size, static_cast<int>(main.size())) - 1;
if (less(main[last_idx], value_to_insert))
{
left = mid + 1;
}
else
{
right = mid;
}
}
insert_pos = main.begin() + (left * group_size);
pend.erase(pend.begin() + start_index * group_size, pend.begin() + (start_index + 1) * 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) std::ostream &operator<<(std::ostream &os, const PmergeMe &obj)
{ {
os << "Vector: " << obj.getPrintableVector() << "\n"; os << "Vector: " << obj.getPrintableVector() << "\n";
os << "Deque: " << obj.getPrintableDeque(); os << "Deque: " << obj.getPrintableDeque();
return os; return os;
} }