Refactor PmergeMe class; implement template-based sorting and insertion methods, enhance timing output, and update VSCode settings
This commit is contained in:
parent
bfbbb4acdd
commit
e696e2a994
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -50,6 +50,7 @@
|
||||
"typeinfo": "cpp",
|
||||
"ctime": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"sstream": "cpp"
|
||||
"sstream": "cpp",
|
||||
"*.tpp": "cpp"
|
||||
}
|
||||
}
|
||||
@ -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<int> &main, std::vector<int> &pend, int start_index, int right, int group_size);
|
||||
|
||||
template <typename Container>
|
||||
void insert(Container &main, Container &pend, int start_index, int right, int group_size);
|
||||
|
||||
template <typename Container>
|
||||
Container sort(Container &data, int level);
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const PmergeMe &obj);
|
||||
|
||||
#include "PmergeMe.tpp"
|
||||
85
ex02/inc/PmergeMe.tpp
Normal file
85
ex02/inc/PmergeMe.tpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "PmergeMe.hpp"
|
||||
|
||||
template <typename Container>
|
||||
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<int>(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<int>(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 <typename Container>
|
||||
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<int>(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<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);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const std::vector<int> &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<int>::const_iterator it = _data_vector.begin(); it != _data_vector.end(); ++it)
|
||||
{
|
||||
if (it != _data_vector.begin())
|
||||
os << " ";
|
||||
os << *it;
|
||||
}
|
||||
os << "\nDeque: ";
|
||||
for (std::deque<int>::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<std::chrono::microseconds>(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<std::chrono::microseconds>(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<int> left = std::vector<int>(_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<int> main;
|
||||
std::vector<int> 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<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 start_index = std::min(jacob_index, static_cast<int>(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<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()))
|
||||
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<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);
|
||||
|
||||
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";
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user