生成稀疏向量的置换

时间:2011-11-04 12:06:05

标签: algorithm permutation

假设我正在尝试生成[21 2 0 34 0 0 0 1]的排列,该排列将最后移动所有的零(请记住,零的数量可能很大,将其视为稀疏向量)向量和非零值将在向量的前面移动,而不改变它们的自然顺序。结果将是[21 2 34 1 0 0 0 0 ]。什么是对这种大型载体具有计算效率的解决方案:

  1. 翻看矢量并将非零元素添加到另一个矢量,然后用零填充第二个矢量的其余部分?
  2. 生成给定向量的所有排列(它们大致为n!/m!,其中n是向量的长度,m是零的数量,如果我们忽略了非零元素,可能出现多次)并选择符合此限制的组合。

3 个答案:

答案 0 :(得分:4)

简单地迭代向量并将每个项目比较为零。如果为零,请记住其索引。如果它不为零并且您正在记住空字段的索引,请将其移动到那里并更改您记住的索引。占用线性时间并且仅需要一个额外存储单元。我想不出更有效的方法来做到这一点。

答案 1 :(得分:1)

最有效的解决方案是迭代向量并将所有非零数字移到零前面。该算法类似于STL的stable_partition算法,其中pred等于'elem!= 0'。

但是如果你需要保留原始矢量,你的第一个想法似乎是最佳的。为了清楚起见,在这种情况下,您应该在处理之前为整个向量分配内存,并相应地填充其元素,而不是在每次迭代时向向量的末尾添加新元素。

答案 2 :(得分:0)

从你建议的解决方案显然第一个更快,因为它运行 O(n)与第二个 O(n!)运行时相反。我可以建议对它进行一些改进,以避免外部内存使用:

保留两个指针:i指向第一个零位置,j指向迭代矢量。在每个步骤中,如果v[ j ] != 0将其值设置为i - 位置并增加i。因此,您将无需额外的记忆。同样,您将执行完全 N + non_zero_elements_qty 迭代,而在您的解决方案中,1次迭代数量为 N + zero_elements_qty ,仍然 O(n)< / strong>,但如果向量相当稀疏则可能会更慢。

以下是C ++中可能的实现:

// input vector<int> v
int n = v.size();
int i = 0;
while( v[ i ] != 0 ) ++i;
for( int j = 0; j < n; ++j )
   if( v[ j ] != 0 )
      v[ i++ ] = v[ j ];