在c ++中选择向量索引的有效方法

时间:2015-01-12 15:04:52

标签: c++

在C ++中,假设您有一个boolean值的向量,并且您希望在与True值对应的索引中随机选择一个索引。

最有效的方法是什么?

示例:

vector<bool> v(4);
v.at(0)=true
v.at(1)=false
v.at(2)=true
v.at(3)=true

您想要在子集{0,2,3}中选择一个数字。

到目前为止,我尝试了两种方法:

  1. 在矢量中堆叠索引,然后在这些元素中进行选择。非常慢。
  2. 朴素方法:随机选择一个索引,直到v.at(rnd_sel_index)True。相当快。
  3. 任何比方法2更快的建议?

2 个答案:

答案 0 :(得分:3)

也许这是一种更有效的方法。

不是存储那些存在的东西,也不存储不存在的东西,或许最好只存储不存在的东西 - 即包含免费索引的矢量。

此向量的顺序可以很容易地随机化一次,然后您可以从back()中提取项目,直到它empty()

如果您想将项目退回到“自由索引池”,只需将它们插入到向量中的随机位置即可。

答案 1 :(得分:1)

您可以使用众所周知的方法从未知长度的序列中选择元素。

示例代码:

#include <random>                                                                                      
#include <iostream>                                                                                    
#include <vector>                                                                                      
#include <algorithm>                                                                                   
std::size_t choose_element(const std::vector<bool>& v) {                                               
  auto last     = v.end();                                                                             
  auto chosen_i = std::find(v.begin(), last, true);                                                    
  auto i        = std::find(std::next(chosen_i), last, true);                                          
  double n      = 2.0;                                                                                 
  static auto random_generator = std::mt19937{std::random_device{}()};                                 
  while (i != last) {                                                                                  
    if (std::bernoulli_distribution(1.0 / n)(random_generator))                                        
      chosen_i = i;                                                                                    
    i = std::find(std::next(i), last, true);                                                           
    ++n;                                                                                               
  }                                                                                                    
  return std::distance(v.begin(), chosen_i);                                                           
}                                                                                                      
int main() {                                                                                           
  std::vector<bool> v = {true, true, false, true};                                                     
  std::vector<int> indexes(v.size());                                                                  
  const double N = 100;                                                                                
  for (int i=0; i<N; ++i)                                                                              
    ++indexes[choose_element(v)];                                                                      
  for (auto& index : indexes)                                                                          
    std::cout << std::distance(indexes.data(), &index) << ": " << (index / N) << "\n";                 
  return 0;                                                                                            
}

这具有可预测的性能,只需要一次通过数据。当然,如果您从同一个向量中获取多个样本,将数据重组为不同的格式然后从中进行绘制可能会更有效。此外,如果几乎所有元素都为真,那么您的方法(2)在一般情况下可能表现更好。