有效搜索数字对

时间:2011-09-28 09:13:26

标签: c++ algorithm

我有一个问题,我有大量的数字对。类似的东西:

(0,  1)
(10, 5)
(5, 6)
(8, 6)
(7, 5)
.....

我需要做的是,如果列表中存在对,我可以进行非常快速的查找。 我的第一个想法是make map< std::pair<int,int> >容器。并使用container.find()进行搜索。

第二个想法是通过使用vector<vector<int>使我可以搜索的std::find(container[id1].begin(),container[id1].end(),id2)容器成对存在;

第二种方式比第一种方式快一点,但如果可能的话,我需要更有效的方法。

所以问题是有更有效的方法来查找列表中是否存在数字对?

启动程序时我知道的对数,所以我不太关心对插入/删除,我只需要非常快速的搜索。

6 个答案:

答案 0 :(得分:4)

如果您不关心插入,可以使用已排序的std :: vector和std :: binary_search,或std :: lower_bound。

int main()
{
    using namespace std;
    vector<pair<int, int>> pairs;
    pairs.push_back(make_pair(1, 1));
    pairs.push_back(make_pair(3, 1));
    pairs.push_back(make_pair(3, 2));
    pairs.push_back(make_pair(4, 1));

    auto compare = [](const pair<int, int>& lh, const pair<int, int>& rh)
        {
            return lh.first != rh.first ? 
                   lh.first < rh.first : lh.second < rh.second;
        };

    sort(begin(pairs), end(pairs), compare);
    auto lookup = make_pair(3, 1);
    bool has31 = binary_search(begin(pairs), end(pairs), lookup, compare);

    auto iter31 = lower_bound(begin(pairs), end(pairs), lookup, compare);

    if (iter31 != end(pairs) && *iter31 == lookup)
        cout << iter31->first << "; " << iter31->second << "at position "
            << distance(begin(pairs), iter31);
}

答案 1 :(得分:2)

std::set可能是要走的路,即使元素数量增加,它也应该表现得相当好(而std::vector的性能会很快减慢,除非你事先对它进行排序某种二进制或树搜索)。请注意,您必须定义<运算符才能使用std::set

如果您可以使用c ++ 0x,std::unordered_set也值得一试,特别是如果您不关心订单。你会在Boost中找到unordered_set。这不需要定义<运算符。如果你使unordered_set具有合适的大小并定义自己的简单散列函数,它不会产生很多碰撞,那么它甚至可能比对有序向量的二进制搜索更快。

答案 2 :(得分:2)

如果您想要快于设置的查找(比O(lg n)更快)并且不关心项目是否是随机顺序,那么哈希表是可行的方法。

这不是标准的一部分,但大多数编译器都可以使用hash_set。它的参考是here

如果您希望真正快速搜索,可以尝试Bloom filter。然而,它们有时会导致误报(即,当没有物品对时检测到物品对),并且需要大量记忆。一个合适的Bloom过滤器实现将是:

const int MAX_HASH = 23879519; // note it's prime; must be 2-5 times larger than number of your pairs
vector<bool> Bloom(MAX_HASH); // vector<bool> compresses bools into bits

// multiply one by a large-ish prime, add the second, return modulo another prime
// then use it as the key for the filter
int hash(long long a, long long b) {
    return (a*15485863LL + b) % MAX_HASH;
}

// constant-time addition
void add_item(pair<int,int> p) {
    Bloom[hash(p.first, p.second)] = true;
}

// constant-time check
bool is_in_set(pair<int,int> p) {
    return Bloom[hash(p.first, p.second)];
}

答案 3 :(得分:1)

您可以使用hash_set的一些实现来加快速度 例如boost :: unordered_set,其中键是std :: pair。 这是最简单方法中最快的。

答案 4 :(得分:1)

如果你的个人数字是int,那么这是另一个解决方案。

  1. 使用两个long long构造int(第一个int可以是高32位,第二个int是低32位)
  2. 将其插入unorderd_set(或set或已排序的vector - 个人资料中以查找您的匹配项)
  3. 找到。
  4. 应该比使用对/元组等更快一些百分比。尤其是。

答案 5 :(得分:-1)

为什么不按照第一个元素排序元组,然后是第二个元素,然后二元搜索应该是O(log(n))。