c++ 在排序时跟踪排列的奇偶性

oxalkeyp  于 2023-03-14  发布在  其他
关注(0)|答案(1)|浏览(132)

std::sort(以及相关的)是STL的皇冠上的宝石之一,然而,当我试图在数值线性代数的上下文中使用它时,我发现它有一个明显的问题,这阻止了我使用它。
关键在于,在数学中,跟踪排列的奇偶性(偶/奇)通常是相关的。
我可以想到两种跟踪奇偶性的方法:
1.用一个平凡的0, 1... n序列压缩排序范围,并在排序后读取置换。(这是一个可靠的方法,但它做了大量不合理的额外工作)。
1.修改比较操作,在每次给定的对未排序时翻转一个符号。当然,一般来说,这是注定要失败的,因为我不知道排列的数量是否与“失败”比较的数量相同。
1.用一个自定义交换将序列 Package 到一个类型中,这个交换的副作用是保留到目前为止排列的计数或符号。
当然,这些都是可怕的解决方案;我正在寻找更好的东西,如果它可用:是否有一种接近std::sort的算法可以让我跟踪奇偶校验,而不必从头开始重新实现排序?

0x6upsns

0x6upsns1#

正如我们建议的那样,你可以只对索引进行排序(使用比较器函数,根据索引处的原始数组),然后用一个O(n)函数在置换后的索引中循环检查奇偶性。

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;

bool parity( const vector<int> &V )    // returns true for even, false for odd
{                                      // V is a permutation of 0, 1, ..., n-1 (NOTE: zero-based!)
   vector<bool> visited( V.size(), false );
   bool result = true;
   for ( int start = 0; start < V.size(); start++ )
   {
      if ( visited[start] ) continue;
      visited[start] = true;
      for ( int j = V[start]; j != start; j = V[j] )
      {
         result = !result;
         visited[j] = true;
      }
   }
   return result;
}

int main()
{
   vector<int> test = { { 17, 0, 19, 13, 4, -5, -6, 27, -31 } };

   vector<int> indices( test.size() );   iota( indices.begin(), indices.end(), 0 );
   sort( indices.begin(), indices.end(), [&test]( int i, int j ){ return test[i] < test[j]; } );
                   
   cout << "Sorted array: ";
   for ( int i : indices ) cout << test[i] << " ";
   cout << "\nParity: " << ( parity( indices ) ? "even" : "odd" ) << '\n';
}
Sorted array: -31 -6 -5 0 4 13 17 19 27 
Parity: odd

相关问题