【问题标题】:boost zip_iterator and std::sort提升 zip_iterator 和 std::sort
【发布时间】:2012-03-09 18:33:42
【问题描述】:

我有两个长度相同的数组valueskeys。 我想使用keys 数组作为键对values 数组进行排序。 有人告诉我,boost 的 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*)’

【问题讨论】:

  • 正如 carl-cook 所指出的,最近(重复)question 给出了一个可行的解决方案。另请注意,Eric Niebler 的范围库提供了 just works 的 view::zip。所述库已被提议用于标准化。

标签: c++ boost


【解决方案1】:

您不能对一对 zip_iterator 进行排序。

首先,make_zip_iterator 将迭代器元组作为输入,因此您可以调用:

boost::make_zip_iterator(boost::make_tuple( ... ))

但这也不会编译,因为keyskeys+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 还需要输入为Writabledescribed here,所以你不能使用排序zip_iterator。

【讨论】:

  • 谢谢。这很有用但是那么我将如何对 values 数组进行按键排序呢?我确信这是在 C++ 中遇到的一个非常常见的操作
  • @curiousexplorer:最简单的方法是将其设为std::pair&lt;int, double&gt;boost::tuple&lt;int, double&gt; 的数组。
【解决方案2】:

关于这个问题的很好的讨论可以在这里找到:https://web.archive.org/web/20120422174751/http://www.stanford.edu/~dgleich/notebook/2006/03/sorting_two_arrays_simultaneou.html

这是这个问题的可能重复:Sorting zipped (locked) containers in C++ using boost or the STL

上面链接中的方法使用std::sort,并且没有额外的空间。它不使用 boost::zip_iterator,只是 boost 元组和 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】:

    在另一个答案中看到你的另一个 cmets 之后。

    虽然我会启发您了解 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 提升::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;
    }
    

    【讨论】:

    • ok 这编译了。但它给了我一个垃圾答案。在正在打印的两列中,第一列完全是 93,第二列是 0.197551
    • 一开始编译的时候我真的很惊讶,你需要自己做一个比较函数
    猜你喜欢
    • 2018-02-22
    • 2014-05-04
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多