【问题标题】:Fastest way to find if same struct exist in a vector查找向量中是否存在相同结构的最快方法
【发布时间】:2013-03-04 19:19:13
【问题描述】:

假设我有一个 people 结构:

struct Person {
    char name[100];
    char surname[100];
    unsigned int age;
};

我想找出最快的方法来搜索并查找向量中是否已经存在具有相同值(相同名称、相同姓氏、相同年龄)的另一个结构。

请记住,我在一个向量中有数百万个。

谢谢

【问题讨论】:

  • 尝试将vector的项目放到set,并使用set的快速查找。
  • 你能举个例子吗?谢谢。
  • 如何对向量进行排序?我的意思是,如果我需要所有内容都匹配,我可以根据姓名、姓氏或年龄对其进行排序吗?
  • 如果它已经通过综合比较器或operator <()对上述所有字段进行了排序,则可以进行简单的二进制搜索。如果不是,则所需的最短时间将是 O(N) 并且需要线性扫描,尽管您可以在发现存在的那一刻提前退出;具有讽刺意味的是,在您的向量中确定它是 not 将花费最长的时间)。如果这将是一个频繁的操作,我会建议一个全面的operator <() 和一个std::set<> 而不是vector<>。构建时间为 O(NlogN),但搜索时间减少到 O(logN)。
  • 只要你放弃可怕的 O(N^2) 或更糟的算法,一百万个这么小的东西几乎没有。

标签: c++ c vector struct


【解决方案1】:

这是一种可能性:

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <tuple>

struct Person {
    std::string name;
    std::string surname;
    unsigned int age;

    bool operator<(const Person &x) const
    {
        return std::tie(name, surname, age) < std::tie(x.name, x.surname, x.age);
    }
};


int main()
{
    std::vector<Person> v;

    // ...

    std::set<Person> s;
    for (const auto &x : v)
    {
        auto i = s.insert(x);
        if (!i.second)
        {
            // x is duplicated
        }
    }
}

对于您的评论,您可以通过这种方式对矢量进行排序:

std::sort(v.begin(), v.end()); // Operator < is overloaded

【讨论】:

  • .find() 逻辑可以去掉,直接使用.insert()。它将为您提供.find(),如果该项目已经存在,请跳过新插入并保留原件。即使这样,返回的迭代器也会包含一个bool,指示插入是否是新的。
  • find可以返回元素的位置吗?或者至少一个属性,例如名称,因为我可以使用 Id 属性来记住重复项,因为我稍后会需要它们。另外你能解释一下为什么我需要同时需要一个向量和一个集合吗?
  • @salamis .insert() 将返回 std::pair&lt;iterator,bool&gt;bool 指示插入是否是新的。如果它是false,那么它不是新的,而是已经存在于集合中。请参阅docs on std::set&lt;&gt; 了解更多信息。
  • 我喜欢你对bool operator&lt; 的非常好的实现。很干净。
【解决方案2】:

根据问题中的cmets,具体来说

不,我的意思是描述 10 与 2、12、54 等重复或 2 与 10、12、54 重复的集合

听起来你真正想要的数据结构是std::multimap(或者std::unordered_multimap,如果你有C++11并且不关心顺序)。 Multimaps 将负责您必须使用 M. M. 的解决方案自己进行的簿记(这总体上很好,除了您必须维护一个带有重复描述的附加容器)。 std::multimap 为您做额外的记账。

#include <map>     // or <unordered_map>
#include <string>
#include <tuple>   // std::tie()
#include <utility> // std::make_pair()

struct Person {
  std::string name;
  std::string surname;
  unsigned int age;

  bool operator<(const Person &x) const
  {
    return std::tie(name, surname, age) < std::tie(x.name, x.surname, x.age);
  }
};

extern bool tryReadNextPersonFromFile(Person &, size_t & record_id);

int main()
{
  std::multimap<Person, size_t> persons;
  Person p;
  size_t rid;

  while(tryReadNextPersonFromFile(p, rid)) {
    persons.insert(std::make_pair(p, rid));
  }

  // ...

  p = ...
  size_t howMany = persons.count(p);
  if(0 == howMany) { /* not found ... */ }
  else {
    auto eq_range = persons.equal_range(p);
    for(auto it=eq_range.first; it != eq_range.second; ++it) {
      size_t pRecordID = it->second;
      // ...
    }
  }
}

为了简洁起见,我使用了很多 C++11 语法(如 auto),但这个想法同样适用于 C++03。由于您之前可能没有听说过多地图(或者至少不熟悉 STL 界面),因此请务必查看例如some documentation,了解您可以使用它做什么以及如何使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 2010-11-24
    • 2019-04-19
    相关资源
    最近更新 更多