C++ 关于std::下界和std::上界的问题

C++ 关于std::下界和std::上界的问题,c++,C++,我正在做的工作是优化具有“几乎”排序数据的数据结构上的查找。我相当有信心,它的“几乎”细节实际上并不重要,但不确定 实际的数据结构比所需的更复杂,所以我简化了它。简化版为std::vector,包含价格、出价和要价: 物价在严格上涨 投标通常按升序排列 请求通常按降序排列 当我说“一般”时,我的意思是数据有一个很长的序列,通常是零,后面是有意义的值,但有些零实际上可能是负的。但是,我只搜索正值,所以所有的零和负值都不是有意义的返回值 以下是我简化的SO程序中的测试数据: //

我正在做的工作是优化具有“几乎”排序数据的数据结构上的查找。我相当有信心,它的“几乎”细节实际上并不重要,但不确定

实际的数据结构比所需的更复杂,所以我简化了它。简化版为
std::vector
,包含价格、出价和要价:

  • 物价在严格上涨
  • 投标通常按升序排列
  • 请求通常按降序排列
当我说“一般”时,我的意思是数据有一个很长的序列,通常是零,后面是有意义的值,但有些零实际上可能是负的。但是,我只搜索正值,所以所有的零和负值都不是有意义的返回值

以下是我简化的SO程序中的测试数据:

//                        Price  Bid  Ask    Index
levels.emplace_back(Level( 42.0,   0, 150)); //  0
levels.emplace_back(Level( 43.0,   0,  71)); //  1
levels.emplace_back(Level( 44.0,   0,  70)); //  2
levels.emplace_back(Level( 45.0,   0,  70)); //  3
levels.emplace_back(Level( 46.0,   0,  69)); //  4
levels.emplace_back(Level( 47.0,   0,   0)); //  5
levels.emplace_back(Level( 48.0,  -1,  -1)); //  6
levels.emplace_back(Level( 49.0,   0,   0)); //  7
levels.emplace_back(Level( 50.0,  80,   0)); //  8
levels.emplace_back(Level( 51.0,  81,   0)); //  9
levels.emplace_back(Level( 52.0,  81,   0)); // 10
levels.emplace_back(Level( 53.0,  82,   0)); // 11
levels.emplace_back(Level( 54.0, 201,   0)); // 12
#include <algorithm>
#include <iostream>
#include <vector>

struct Level final {
    Level() = delete;
    Level(const double a_price, const int a_bid, const int a_ask) :
        m_price(a_price),
        m_bid  (a_bid),
        m_ask  (a_ask)
    {}

    const double m_price;
    const int    m_bid;
    const int    m_ask;
};

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cout << "Usage: " << argv[0] << " <Seek Bid> <Seek Ask>\n";
        exit(1);
    }

    std::vector<Level> levels;

    //                        Price  Bid  Ask    Index
    levels.emplace_back(Level( 42.0,   0, 150)); //  0
    levels.emplace_back(Level( 43.0,   0,  71)); //  1
    levels.emplace_back(Level( 44.0,   0,  70)); //  2
    levels.emplace_back(Level( 45.0,   0,  70)); //  3
    levels.emplace_back(Level( 46.0,   0,  69)); //  4
    levels.emplace_back(Level( 47.0,   0,   0)); //  5
    levels.emplace_back(Level( 48.0,  -1,  -1)); //  6
    levels.emplace_back(Level( 49.0,   0,   0)); //  7
    levels.emplace_back(Level( 50.0,  80,   0)); //  8
    levels.emplace_back(Level( 51.0,  81,   0)); //  9
    levels.emplace_back(Level( 52.0,  81,   0)); // 10
    levels.emplace_back(Level( 53.0,  82,   0)); // 11
    levels.emplace_back(Level( 54.0, 201,   0)); // 12

    const int seekBid = atoi(argv[1]);
    const int seekAsk = atoi(argv[2]);
    std::cout << "Seek Bid: " << seekBid << ", Seek Ask: " << seekAsk << '\n';

    if (seekBid <= 0 || seekAsk <= 0) {
        std::cout << "Seek Bid or Seek Ask is not positive\n";
        exit(1);
    }

    // If the last Level's Bid is < Seek Bid then what I am looking for doesn't exist
    if (levels.back().m_bid < seekBid)
        std::cout << "Cannot satisfy Seek Bid\n";
    else {
        // Find the first Level with a Bid <= Seek Bid
        // Not sure why I need to specify < instead of <= but appears to work
        const auto it = std::lower_bound(
            levels.begin(),
            levels.end(),
            seekBid,
            [](const Level& a_level, const int a_bid) { return a_level.m_bid < a_bid; }
        );
        std::cout << "Bid Price: " << it->m_price << ", Bid Index: " << &*it - &levels[0] << '\n';
    }

    // If the first Level's Ask is < Seek Ask then what I am looking for doesn't exist
    if (levels.front().m_ask < seekAsk)
        std::cout << "Cannot satisfy Seek Ask\n";
    else {
        // Find the last Level with Ask <= Seek Ask
        // Need to use std::prev due to how std::upper_bound works
        // Not sure why I need to specify < instead of <= but appears to work
        const auto it = std::prev(std::upper_bound(
            levels.begin(),
            levels.end(),
            seekAsk,
            [](const int a_ask, const Level& a_level) { return a_level.m_ask < a_ask; }
        ));
        std::cout << "Ask Price: " << it->m_price << ", Ask Index: " << &*it - &levels[0] << '\n';
    }

    return 0;
}
当我在这个结构中搜索某个出价“Seek Bid”时,我想找到出价大于或等于“Seek Bid”的第一级价格

当我在这个结构中搜索某个Ask“Seek Ask”时,我想找到最后一个级别的价格,该级别的Ask大于或等于“Seek Ask”

下面是我的SO简化程序:

//                        Price  Bid  Ask    Index
levels.emplace_back(Level( 42.0,   0, 150)); //  0
levels.emplace_back(Level( 43.0,   0,  71)); //  1
levels.emplace_back(Level( 44.0,   0,  70)); //  2
levels.emplace_back(Level( 45.0,   0,  70)); //  3
levels.emplace_back(Level( 46.0,   0,  69)); //  4
levels.emplace_back(Level( 47.0,   0,   0)); //  5
levels.emplace_back(Level( 48.0,  -1,  -1)); //  6
levels.emplace_back(Level( 49.0,   0,   0)); //  7
levels.emplace_back(Level( 50.0,  80,   0)); //  8
levels.emplace_back(Level( 51.0,  81,   0)); //  9
levels.emplace_back(Level( 52.0,  81,   0)); // 10
levels.emplace_back(Level( 53.0,  82,   0)); // 11
levels.emplace_back(Level( 54.0, 201,   0)); // 12
#include <algorithm>
#include <iostream>
#include <vector>

struct Level final {
    Level() = delete;
    Level(const double a_price, const int a_bid, const int a_ask) :
        m_price(a_price),
        m_bid  (a_bid),
        m_ask  (a_ask)
    {}

    const double m_price;
    const int    m_bid;
    const int    m_ask;
};

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cout << "Usage: " << argv[0] << " <Seek Bid> <Seek Ask>\n";
        exit(1);
    }

    std::vector<Level> levels;

    //                        Price  Bid  Ask    Index
    levels.emplace_back(Level( 42.0,   0, 150)); //  0
    levels.emplace_back(Level( 43.0,   0,  71)); //  1
    levels.emplace_back(Level( 44.0,   0,  70)); //  2
    levels.emplace_back(Level( 45.0,   0,  70)); //  3
    levels.emplace_back(Level( 46.0,   0,  69)); //  4
    levels.emplace_back(Level( 47.0,   0,   0)); //  5
    levels.emplace_back(Level( 48.0,  -1,  -1)); //  6
    levels.emplace_back(Level( 49.0,   0,   0)); //  7
    levels.emplace_back(Level( 50.0,  80,   0)); //  8
    levels.emplace_back(Level( 51.0,  81,   0)); //  9
    levels.emplace_back(Level( 52.0,  81,   0)); // 10
    levels.emplace_back(Level( 53.0,  82,   0)); // 11
    levels.emplace_back(Level( 54.0, 201,   0)); // 12

    const int seekBid = atoi(argv[1]);
    const int seekAsk = atoi(argv[2]);
    std::cout << "Seek Bid: " << seekBid << ", Seek Ask: " << seekAsk << '\n';

    if (seekBid <= 0 || seekAsk <= 0) {
        std::cout << "Seek Bid or Seek Ask is not positive\n";
        exit(1);
    }

    // If the last Level's Bid is < Seek Bid then what I am looking for doesn't exist
    if (levels.back().m_bid < seekBid)
        std::cout << "Cannot satisfy Seek Bid\n";
    else {
        // Find the first Level with a Bid <= Seek Bid
        // Not sure why I need to specify < instead of <= but appears to work
        const auto it = std::lower_bound(
            levels.begin(),
            levels.end(),
            seekBid,
            [](const Level& a_level, const int a_bid) { return a_level.m_bid < a_bid; }
        );
        std::cout << "Bid Price: " << it->m_price << ", Bid Index: " << &*it - &levels[0] << '\n';
    }

    // If the first Level's Ask is < Seek Ask then what I am looking for doesn't exist
    if (levels.front().m_ask < seekAsk)
        std::cout << "Cannot satisfy Seek Ask\n";
    else {
        // Find the last Level with Ask <= Seek Ask
        // Need to use std::prev due to how std::upper_bound works
        // Not sure why I need to specify < instead of <= but appears to work
        const auto it = std::prev(std::upper_bound(
            levels.begin(),
            levels.end(),
            seekAsk,
            [](const int a_ask, const Level& a_level) { return a_level.m_ask < a_ask; }
        ));
        std::cout << "Ask Price: " << it->m_price << ", Ask Index: " << &*it - &levels[0] << '\n';
    }

    return 0;
}
所有这些结果都是正确的,但我的问题是:

  • 我有必要把所有的负一变成零吗 在搜索之前,确保在使用前得到正确的结果
    std::lower_bound
    std::upper_bound
    考虑到我只是 寻找正值?换句话说,做那些消极的 根据我的搜索要求,是否会导致任何未定义的行为
  • 关于
    std::lower_bound
    如何工作的说明 en.cppreference.com和cplusplus.com非常令人困惑,我只是 意识到使用
    几乎所有(有序的)stl容器都依赖于严格的弱有序。严格弱序定义了元素的相对位置,即一个项优先于另一项

    因此,严格弱序具有以下性质:

    • 对于S中的所有x,x
    • 对于S中的所有x,y,如果x
    • 对于S中的所有x,y,z,如果x
    • 对于S中的所有x,y,z,如果x与y不可比(x
    如果您希望这些STL容器和算法按照指定的方式工作,那么您提供的比较必须提供这种严格的弱排序

    参考资料,更多详情:


    中描述了一般要求。必须有一个单一的顺序,以便使用提供的比较,等价元素组在该顺序中有一个特定的位置<代码>下界
    上界
    要求输入的顺序是这样的

    我有必要在搜索之前将所有的负1变成零,以确保结果正确

    在这种特殊情况下不适用,因为它只针对给定的正值测试
    Level
    s,而不针对彼此。您的
    comp
    0
    视为等同于
    -1
    ,因此它们“出故障”并不重要。在此数据集中搜索
    0
    或负数将是未定义的行为


    为什么使用
    std::lower_bound
    std::upper_bound
    执行简单的二进制搜索不是“正确的”。它们不搜索特定的元素值,而是搜索一个分区点。不需要对您应用的
    std::lower_bound
    范围进行排序。最重要的是:

    必须根据表达式
    元素
    comp(元素,值)
    对范围
    [第一,最后)
    进行分区,即表达式为
    真的所有元素必须位于表达式为
    假的所有元素之前


    我有必要在搜索之前把所有的负一都变成零吗

    否。如果
    value
    为正,则始终根据表达式
    元素
    对范围进行分区


    为什么它不是“正确的”使用
    的原因是,大多数这些算法/数据结构化都需要a,也请看您对我的第一个问题的回答确实很有帮助,但您能澄清您对我的第二个问题的回答吗?我目前使用
    std::lower_bound
    std::upper_bound
    分别进行出价和出价和出价,都得到了正确的结果你能澄清第二个答案吗?对我来说,
    !(b
    意味着
    b>=a,所以我不明白yet@asimes,
    lower_bound
    说:给我一个范围,一个
    值,一个
    a
    关系,我会给你(的位置)第一个元素
    >=value
    返回。如果您给它