【问题标题】:subtract two order-less std::vector of objects减去对象的两个无序 std::vector
【发布时间】:2015-12-29 09:38:01
【问题描述】:

我有两个对象向量。比如:

std::vector<thing> all_things;
std::vector<thing> bad_things;

我想获得包含 good_things 的第三个向量。换句话说,all_thing 中不属于 bad_things 的每个对象:

std::vector<thing> good_things=subtract(all_things,bad_things);

关于如何以最有效和最标准的方式实施减法的任何想法。

P.S 向量可以 排序,因为类 thing 没有任何要排序的东西。 谢谢!

编辑: 我不想对all_things 进行任何更改。 例如

void substract(const std::vector<thing>& a, const std::vector<thing>& b);

【问题讨论】:

  • 你的向量中的元素是独一无二的吗?
  • @PaoloM std::set 需要排序(OP 声明这是不可能的),因此如果元素是唯一的,他应该使用 std::unordered_set
  • thing 是否有合适的 operator== 或等效项?
  • 我很难想象无法订购的东西。如果所有其他方法都失败,请使用 memcmpstd::sort,然后进行线性擦除。
  • 那么为什么不按位图的 RGB 值对thing 进行排序呢?

标签: c++ c++11 vector


【解决方案1】:

从 cmets 中,您的 things 可以排序,但没有意义。

没关系。

对它们进行无意义的排序。

编写一个函数,接受两个things 并给它们一个一致的无意义顺序,并且两个事物只有在它们相等时才会相互比较。

打电话给bool arb_order_thing(thing const&amp;, thing const&amp;)

现在std::sort 两个向量并使用std::set_difference

现在,如果复制成本很高,这可能会很昂贵。因此,改为创建thing const* 的两个向量,写入bool arb_order_thing_ptr(thing const*, thing const*)(它使用无意义的排序取消引用和比较),使用它对指针向量进行排序,使用它使用set_difference,然后转换回vector&lt;thing&gt;

或者,考虑编写一个thing const* 哈希(不是std::hash&lt;thing*&gt;,因为这是全局且粗鲁的)并使用unordered_set&lt;thing const*&gt;s 手动完成工作。散列两个向量中较小的一个,然后针对另一个向量上的散列进行std::copy_if 测试。

【讨论】:

    【解决方案2】:

    如果您不能订购它们,您可以使用蛮力方式。只需比较向量。例如:

    std::vector<Thing> all;
    std::vector<Thing> bad;
    std::vector<Thing> good (all.size());
    auto it = std::copy_if (all.begin(), all.end(), good.begin(), 
        [&bad](const Thing& t){return std::find(bad.begin(), bad.end(), t) == bad.end();} );
    all.resize(std::distance(all.begin(),it));
    

    【讨论】:

    • 为什么要调整all 的大小?为什么要部分形成子范围 [it, good.end()) 中的条目?
    • +1 另外,不要对使用 std::vector 的蛮力而不是使用另一个容器感到难过。根据您的情况,它实际上可能是最快的方法,这要归功于 vector 将其值放置在单个连续分配中。
    • 最后一行似乎不起作用。 Live example.
    • 你为什么要在good中默认构造这么多Things,这是无用且可以避免的?
    • @NickyC:因为这是一个非常糟糕的例子。您可以只使用后插入器而不调整大小。这在很大程度上取决于用例。所以对于这个问题,你怎么做是毫无意义的。
    【解决方案3】:

    如果thing 的构造/复制成本很高,并且它的容器很长而且坏的东西很多,那么构造一个同样长的“不错”数组就不是一个好主意。实际上,必须根据thing 比较填充 all.size() x good.size() 的标志矩阵。如果确保唯一性,则可以避免遍历坏处。但是 O(N2) 无论如何都是复杂度。

    【讨论】:

      【解决方案4】:

      我想推荐类似于 mkaes 的代码,但需要做一些调整:

      std::vector<thing> substract(const std::vector<thing>& a, const std::vector<thing>& b) {
          std::vector<thing> sub;
          sub.reserve(a.size());
          for (const auto &item : a) {
              if (std::find(b.begin(), b.end(), item) == b.end()) {
                   sub.push_back(a);
              }
          }
          return sub;
      }
      

      这是您想要实现的目标的残酷版本。但这是你能做的最好的事情,如果你不能对向量的元素进行排序。但请记住,您需要能够比较 item 类型的两个对象,这意味着您需要提供 operator==

      【讨论】:

      • 改进?也许不是,但它不会不必要地触发all.size() 默认构造函数。 thing 类型的默认构造函数甚至不必存在。还是调用reserve 比触发重新分配要好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-19
      • 1970-01-01
      • 2021-02-26
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      相关资源
      最近更新 更多