Увеличить zip_iterator и std:: sort
У меня есть два массива values
и keys
с одинаковой длиной.
Я хочу сортировать по ключу массив values
, используя массив keys
в качестве ключей.
Мне сказали, что ускоритель zip-итератор - это всего лишь правильный инструмент для блокировки двух массивов вместе и одновременно с ними делать вещи.
Вот моя попытка использовать boost:: zip_iterator для решения проблемы сортировки, которая не скомпилируется с помощью gcc
. Может кто-нибудь помочь мне исправить этот код?
Задача лежит в прямой
std::sort ( boost::make_zip_iterator( keys, values ), boost::make_zip_iterator( keys+N , values+N ));
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
int main(int argc, char *argv[])
{
int N=10;
int keys[N];
double values[N];
int M=100;
//Create the vectors.
for (int i = 0; i < N; ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator( keys, values ),
boost::make_zip_iterator( keys+N , values+N )
);
//The values array and the corresponding keys in ascending order.
for (int i = 0; i < N; ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}
ПРИМЕЧАНИЕ. Сообщение об ошибке при компиляции
g++ -g -Wall boost_test.cpp
boost_test.cpp: In function ‘int main(int, char**)’:
boost_test.cpp:37:56: error: no matching function for call to ‘make_zip_iterator(int [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)], double [(((unsigned int)(((int)N) + -0x00000000000000001)) + 1)])’
boost_test.cpp:38:64: error: no matching function for call to ‘make_zip_iterator(int*, double*)’
Ответы
Ответ 1
Вы не можете сортировать пару zip_iterators.
Во-первых, make_zip_iterator берет кортеж итераторов в качестве входных данных, поэтому вы можете вызвать:
boost::make_zip_iterator(boost::make_tuple( ... ))
но это тоже не скомпилируется, потому что keys
и keys+N
не имеют одного и того же типа. Нам нужно заставить keys
стать указателем:
std::sort(boost::make_zip_iterator(boost::make_tuple(+keys, +values)),
boost::make_zip_iterator(boost::make_tuple(keys+N, values+N)));
это будет скомпилировано, но отсортированный результат все еще не прав, поскольку zip_iterator моделирует только Readable iterator, но std::sort
также нуждается в вход Writable как описанный здесь, так что вы не может сортировать с помощью zip_iterator.
Ответ 2
Очень хорошее обсуждение этой проблемы можно найти здесь: https://web.archive.org/web/20120422174751/http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html
Вот возможный дубликат этого вопроса: Сортировка сжатых (заблокированных) контейнеров в С++ с использованием boost или STL
В приведенном выше соединении используется std:: sort и без дополнительного пространства. Он не использует boost:: zip_iterator, просто увеличивает кортежи и фасад итератора boost. Std:: tuples также должен работать, если у вас есть современный компилятор.
Если вы счастливы иметь один дополнительный вектор (из элементов size_t), тогда следующий подход будет работать в средстве с временным интервалом ~ o (n log n). Это довольно просто, но там будут лучшие подходы, если вы их найдете.
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename T1, typename T2>
void sortByPerm(vector<T1>& list1, vector<T2>& list2) {
const auto len = list1.size();
if (!len || len != list2.size()) throw;
// create permutation vector
vector<size_t> perms;
for (size_t i = 0; i < len; i++) perms.push_back(i);
sort(perms.begin(), perms.end(), [&](T1 a, T1 b){ return list1[a] < list1[b]; });
// order input vectors by permutation
for (size_t i = 0; i < len - 1; i++) {
swap(list1[i], list1[perms[i]]);
swap(list2[i], list2[perms[i]]);
// adjust permutation vector if required
if (i < perms[i]) {
auto d = distance(perms.begin(), find(perms.begin() + i, perms.end(), i));
swap(perms[i], perms[d]);
}
}
}
int main() {
vector<int> ints = {32, 12, 40, 8, 9, 15};
vector<double> doubles = {55.1, 33.3, 66.1, 11.1, 22.1, 44.1};
sortByPerm(ints, doubles);
copy(ints.begin(), ints.end(), ostream_iterator<int>(cout, " ")); cout << endl;
copy(doubles.begin(), doubles.end(), ostream_iterator<double>(cout, " ")); cout << endl;
}
Ответ 3
После просмотра другого комментария в другом ответе.
Я бы просветил вас на std:: map. Это контейнер ключевых значений, который сохраняет порядок ключей. (это в основном двоичное дерево, обычно красное черное дерево, но это не важно).
size_t elements=10;
std::map<int, double> map_;
for (size_t i = 0; i < 10; ++i)
{
map_[rand()%M]=1.0*rand()/RAND_MAX;
}
//for every element in map, if you have C++11 this can be much cleaner
for (std::map<int,double>::const_iterator it=map_.begin();
it!=map_.end(); ++it)
{
std::cout << it->first << "\t" << it->second << std::endl;
}
непроверено, но любая ошибка должна быть простой ошибкой синтаксиса
Ответ 4
boost::make_zip_iterator
взять boost:: tuple.
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
int main(int argc, char *argv[])
{
std::vector<int> keys(10); //lets not waste time with arrays
std::vector<double> values(10);
const int M=100;
//Create the vectors.
for (size_t i = 0; i < values.size(); ++i)
{
keys[i] = rand()%M;
values[i] = 1.0*rand()/RAND_MAX;
}
//Now we use the boost zip iterator to zip the two vectors and sort them "simulatneously"
//I want to sort-by-key the keys and values arrays
std::sort ( boost::make_zip_iterator(
boost::make_tuple(keys.begin(), values.begin())),
boost::make_zip_iterator(
boost::make_tuple(keys.end(), values.end()))
);
//The values array and the corresponding keys in ascending order.
for (size_t i = 0; i < values.size(); ++i)
{
std::cout << keys[i] << "\t" << values[i] << std::endl;
}
return 0;
}