【问题标题】:Sort vector by even and odd indices. c++按偶数和奇数索引对向量进行排序。 C++
【发布时间】:2015-11-18 18:45:56
【问题描述】:

是否有一个单行(或简单的无循环)解决方案可以通过偶数和奇数索引对向量进行排序? 示例:

long entries[] = {0,1,2,10,11}; // indices 0 1 2 3 4
std::vector<long> vExample(entries, entries + sizeof(entries) / sizeof(long) );

vExample.sortEvenOdd(vExample.begin(),vExample.end()); // magic one liner I wish existed...

for (int i = 0; i < vExample.size(); i++)
{
    std::cout << vExample[i] << " ";
}

现在我想得到以下输出:

0 2 11 1 10 // corresponding to indices 0 2 4 1 3

【问题讨论】:

  • 使用std::end(entries)而不是长表达式计算它
  • 这也有效:std::vector&lt;long&gt; vExample{0,1,2,10,11}
  • 如果你可以使用 Boost,boost.strided 就是你所需要的。这样,您甚至不必实际重新排序向量,这可能有助于提高性能。

标签: c++ vector std


【解决方案1】:

我试着做一个真正的一个班轮

  std::stable_partition(std::begin(input), std::end(input),
                        [&input](int const& a){return 0==((&a-&input[0])%2);});

这是完整的程序:

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
  std::vector<int> input {0,1,2,10,11};

  std::stable_partition(std::begin(input), std::end(input),
                        [&input](int const& a){return 0==((&a-&input[0])%2);});

  for (auto v : input)
    std::cout << v << " ";
}

好的,我知道,它起作用的唯一原因是 vector 使用了一个连续的项目数组并且整个事情很脏......但因为这是 OP 要求的一个衬里,它不需要任何额外的东西提升...

【讨论】:

    【解决方案2】:

    这不是一个班轮,但非常接近:

    long entries[] = {0,1,2,10,11}; // indices 0 1 2 3 4
    std::vector<long> vExample;
    for( bool flag : { true, false } ) {
        auto cond = [&flag]( long ) { flag = !flag; return !flag; };
        std::copy_if( std::begin( entries ), std::end( entries ), std::back_inserter( vExample ), cond );
    }
    

    【讨论】:

      【解决方案3】:

      如果你可以使用 Boost,这非常简洁:

      #include <boost/range/adaptor/strided.hpp>
      #include <boost/range/adaptor/sliced.hpp>
      #include <boost/range/algorithm_ext/push_back.hpp>
      #include <iostream>
      #include <vector>
      
      int main() {
          using namespace boost::adaptors;
      
          std::vector<int> input {0,1,2,10,11};
          std::vector<int> partitioned;
      
          boost::push_back(partitioned, input | strided(2));
          boost::push_back(partitioned, input | sliced(1, input.size()) | strided(2));
      
          for (auto v : partitioned)
              std::cout << v << " ";
      }
      

      您当然可以将其包装在一个函数中,以便在调用代码中获得一个单行。 Live

      【讨论】:

        【解决方案4】:

        我不喜欢摆弄@fjardon 接受的答案提出的地址的混乱事务。 @Slava 的建议要好得多,并结合 OP 的代码给出了一些效果很好的东西:

        int main() {
           std::vector<int> vals {0,2,3,-3,8,-5,7,8};
          bool flag = true;
            std::stable_partition(begin(vals), end(vals), [&flag] (auto el) mutable
                                  {
                                    // toggle flag, return previous value
                                    flag = !flag; return !flag;
                                  });
            for (auto v : vals)
                std::cout << v << " ";
        } 
        
        Output: 0 3 8 7 2 -3 -5 8
        

        【讨论】:

        • 顺便说一句,您可以使用[flag = true],它将与mutable AFAIK 一起使用。
        • FWIW 您也可以省略参数名称并留下 (auto) ,否则编译器可能会抱怨未使用的变量。否则[[maybe_unused]] 会起作用。
        • 最后一件更偏爱的事情,我宁愿计算并检查是否均匀,而不是为其设置标志。这给了我这个 lambda 函数:[index = 0](auto) mutable { return index++ % 2 == 0; }
        【解决方案5】:

        您需要的是stable_partition。定义一个谓词来检查索引是否甚至使用模 2,然后你就可以开始了。

        【讨论】:

        • stable_partition 通过交换工作;当一个元素的索引发生变化时,它会变得混乱吗?
        • 你能举一个这个谓词的例子吗?
        • 这个答案很不完整,完全不清楚如何用stable_partition来做到这一点。
        • 最重要的是如何证明std::stable_partition 可以正常工作,因为仅仅一两个测试用例是不够的。例如,如果它不能分配额外的缓冲区行为就会改变。
        • @BenjaminLindley 查看我对谓词的回答。我并不为此感到自豪,但为了挑战,我做到了......
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-24
        相关资源
        最近更新 更多