使用启动步骤停止方案(C ++)循环通过不同变量的所有组合的高速解决方案

时间:2018-02-26 13:45:26

标签: c++ recursion iteration combinations permutation

我正在寻找一种高速解决方案,通过启动步骤停止方案来循环具有不同变量的所有组合的功能。 仅在运行时才知道哪些变量被激活用于组合。 (use = false / true)。

可能的解决方案可以使用递归或反向跟踪,但对于应用程序来说太慢了。

对我而言,挑战是:

  • 高性能!不使用递归或反向跟踪。也许是一个快速的迭代解决方案?
  • 处理double和int数据类型。
  • 处理仅在运行时知道哪些变量被激活用于组合。 (use = false / true)
  • 仅在运行时处理该组合的已知/开始/步骤/停止。
  • 功能使用正常值(例如i1_value)。在循环期间,通过组合更改值(如果use = true)。

解决方案怎么样?

在此示例中,所有活动变量的可能组合为10 * 11 * 21 = 2310 实际上有更多的变量和更多可能的组合,可能高达数百万(需要高性能解决方案的原因)。

int i1_use = true;
int i1_value = 1; // the normal value that the function use 
int i1_start_value = 1;
int i1_step_value = 2;
int i1_stop_value = 20;
// 1,3,5,7,9,11,13,15,17,19 
// -> gives 10 different values

int i2_use = false;
int i2_value = 100; // the normal value that the function use 
int i2_start_value = 1000;
int i2_step_value = 500;
int i2_stop_value = 3000;
// -> use = false! no combination!

double d1_use = true;
double d1_value = 1.234; // the normal value that the function use 
double d1_start_value = 0;
double d1_step_value = 0.02;
double d1_stop_value = 0.2;
// 0,0.02,0.04,0.06,0.08,0.1,0.12,0.14,0.16,0.18,0.2  
// -> gives 11 different values

double d2_use = true;
double d2_value = 10; // the normal value that the function use 
double d2_start_value = 10;
double d2_step_value = 0.5;
double d2_stop_value = 20;
// 10,10.5,11,11.5,12,12.5,13,13.5,14,14.5,15,15.5,16,16.5,17,17.5,18,18.5,19,19.5,20 
// -> gives 21 different values

// All combinations 10*11*21 = 2310

1 个答案:

答案 0 :(得分:0)

首先,将变量组合成结构是合理的。但假设代码的其余部分保持原样,我建议不管怎样创建一个辅助构造:

// an interface to use in vector
class CombinatorInterface {
   public:
   virtual bool nextValue() = 0;
};

// and template implementation for different types (int, float, etc.)
template <typename T>
class Combinator: public CombinatorInterface {
    public:
    Combinator(bool inUse, T currentValue, T startValue, T stepValue, T stopValue) :
      _inUse{inUse},
      _currentValue{currentValue},
      _startValue{startValue},
      _stepValue{stepValue},
      _stopValue{stopValue}
    {}


    // Now this is overly simplified, as you might need better error checks and maybe different approaches for integral and float types
    bool nextValue() override {
        if (_inUse == false) {
            return false;
        }

        if (_currentValue < _stopValue) {
            _currentValue += _stepValue;
            return true;
        } else {
            return false;
        }
    }

    private:
    bool& _inUse;
    T& _currentValue;
    T& _startValue;
    T& _stepValue;
    T& _stopValue;
};

然后您可以在以下代码中使用此构造:

std::vector<CombinatorInterface*> v;
v.push_back(new Combinator<int>(i1_use , i1_value, i1_start_value, i1_step_value , i1_stop_value));
    // more like this
    v.push_back(new Combinator<double>(d2_use, d2_value, d2_start, d2_step_value, d2_stop_value));

    bool permutationAvailable = true;
    do {
        permutationAvailable = false;
        for (auto i: v) {
            if (i->nextValue()) {
                permutationAvailable = true;
                break;
            }
        // do your measurements for every iteration
        }
    } while(permutationAvailable);
    // do the part after there are no more iterations

现在这将使用address_size * parameters * 5内存,如果你只使用一组变量就可以消除,即在整个代码中使用相同的向量。

另一个开销是多态基,这将导致每个nextValue()调用的额外地址查找。否则这将是一个简单的暴力迭代。