找出向量中的所有元素是假还是真 c++ 的最快方法

Fastest way to find out if all elements in a vector are false or true c++?

本文关键字:方法 c++ 元素 向量      更新时间:2023-10-16

我想知道是否有一种快速的方法可以找出向量中的所有元素是的还是真的?就像而不是使用循环检查每个元素?

为了

清楚起见,我会利用新算法

// all true
std::all_of(vec.begin(), vec.end(), [](bool v) { return v; });
// all false
std::all_of(vec.begin(), vec.end(), [](bool v) { return !v; });
std::none_of(vec.begin(), vec.end(), [](bool v) { return v; });

如果不实际检查向量的每个元素,就无法确定向量中的所有元素是否为真。最好的情况是,你以不同的方式重新解释内存,一次检查一个以上的元素,但你仍然必须检查所有内容,直到找到一个不合格的元素。

最简单的IMO是免费find函数

if (std::find(begin(v), end(v), true) == end(v)) // All false

您也可以使用 std::accumulate()

int sum = std::accumulate(std::begin(v), std::end(v), 0);
if (sum == v.size()) {
    // All true
}
else if (sum) {
    // Any true, any false
}
else {
    // All false
}

这需要循环,但至少会利用短周期行为。

bool all = true;
std::vector<bool>::iterator it = myVec.begin();
while(all && it != myVec.end())  // Stops early if it hits a false
{
    all &= *it;
    ++it;
}

如果alltrue,向量中的所有元素都是真的。如果all为假,则至少有一个元素未true

我也同意最坏的情况是必须检查每个单独的元素,但对于所有其他情况,我建议改写这个问题:

我的收藏中的所有元素都一样吗?如果是这样,价值是多少。

在这两种情况下,这将提前返回,您就完成了。否则,还必须检查元素的值(真或假(。

为此,我建议看这里。

我想更概括一下我的答案:这可以使用任何 N 个互斥谓词 A1、... 、AN 来完成,我想检查我的集合。为此,我将需要一个函数,给定我集合的一个元素,返回该元素的谓词 Ai 的一些标识符(以及检查谓词相等的方法(。

然后我可以再次应用上述方案。

我认为最有效的是:

if(v.find(v.begin(), v.end(), true) == v.end())
// All false  
if(v.find(v.begin(), v.end(), false) == v.end())
// All true

对于大向量,更有效的选择是用vector<bitset>替换vector<bool>。然后,您可以简单地将 any_of() 算法与调用 bitset 成员函数的 lambda 函数结合使用any()(或类似地用于 all_of()all() (。

    int n = 2000000000, i = 623;
    vector<bitset<256>> bits((n + 255) / 256);
    bits[i >> 8][i & 0xFF] = true;
    cout << bits[i >> 8][i & 0xFF] << endl;
    if (any_of(bits.begin(), bits.end(),
            [](const bitset<256>& bs) { return bs.any(); })) {
        cout << "at least one bit set" << endl;
    }
    for (auto& bs : bits) {
        bs.set();
    }
    if (all_of(bits.begin(), bits.end(),
            [](const bitset<256>&bs) { return bs.all(); })) {
        cout << "all bits set" << endl;
    } 

在我对 20 亿个元素(发布版本 VS2022(的计时测试中,any_of() 或上述all_of()需要 20 毫秒(如果any_of()提前爆发,则更快(。而对于vector<bool>,它们需要 2200 毫秒。大约 100 倍加速。设置所有位需要36ms,而vector<bool>为1930ms,大约是50倍的加速。

界面有点混乱,所以如果你想清理它,你可以把它包装在模板类中:

template <size_t bits_per_bitset, int lg_bits_per_bitset>
class dynamic_bitset {
public:
    dynamic_bitset(int n)
        : v((n + bits_per_bitset - 1)/ bits_per_bitset) { }
    
    constexpr bool operator[](int i) const {
        return v[i >> lg_bits_per_bitset][i & ((1 << lg_bits_per_bitset) - 1)];
    }
    auto operator[](int i) {
        return v[i >> lg_bits_per_bitset][i & ((1 << lg_bits_per_bitset) - 1)];
    }
    bool any() {
        return any_of(v.begin(), v.end(),
            [](const std::bitset<bits_per_bitset>& bs) { return bs.any(); });
    }
    bool all() {
        return all_of(v.begin(), v.end(),
            [](const std::bitset<bits_per_bitset>& bs) { return bs.all(); });
    }
    void set()   { for (auto& bs : v) bs.set(); }
    void reset() { for (auto& bs : v) bs.reset(); }
    void flip()  { for (auto& bs : v) bs.flip(); }
private:
    std::vector<std::bitset<bits_per_bitset>> v;
};

现在使用它就像这样简单:

    int n = 2000000000, i = 623;
    dynamic_bitset<256, 8> bits(n);
    bits[i] = true;
    cout << bits[i] << endl;
    if (bits.any()) {
        cout << "at least one bit set" << endl;
    }
    bits.set();
    if (bits.all()) {
        cout << "all bits set" << endl;
    }

如果我增加模板参数,它会变得更快一些,但如果n不能被 bits_per_bitset 整除,则会增加浪费的空间。在我的实验中,除了<1024,10>之外没有进一步的回报,它至少占用32个单词,每个单词32位。

您可以添加一堆其他操作来轻松dynamic_bitset,包括push_back(),按位运算符,begin()/end()等。