c++ - 最小划分对象 vector (C++)

标签 c++ partitioning

我有一个 std::vector 对象,其中 vector 中的每个元素或多或少看起来像:

struct Obj {
  int group;
};

vector 中的条目没有特定的顺序。通常,在分区时,人们可能希望通常将具有某些共同点的同一分区中的元素分组,但是,在我的情况下,我想要的实际上是重新排列此 vector 中的条目并以使用的方式对其进行分区可能的绝对最小分区数,其中单个分区中的每个元素与同一分区中的每个其他元素属于不同组。

这是否可以在不迭代 vector 的每个排列并查看每个排列有多少个分区的情况下实现?

编辑:

有人要求举个例子,所以我会尝试提供一个。

如果对象的初始 vector 是

[ {1}, {2}, {3}, {2}, {3}, {1}, {4}, {5}, {3}, {2} ]

最佳分区是将其分为三个分区,如下所示:

[ {1}, {2}, {3}, {4}, {5} ] [ {1}, {2}, {3} ] [{2}, {3} ]

因此在每个分区内,所有条目都属于不同的组。

最佳答案

如果我对您的要求理解正确,那么“最小分区数”由原始 vector 中单个值的最大频率给出。所以你可以创建一个直方图,然后在其中找到最大条目。 (这与 vector 的大小成线性关系。)现在创建 m 个 vector (其中 m 是刚刚确定的最大频率)并分配每个 m 与其中之一相同的值。保证您可以以分区中不会出现重复的方式分配剩余元素。

在大小为 n 的输入 vector v 的伪代码中:

  • 初始化一个空直方图H
  • 对于 v 中的每个项目 x:
    • H[x] 递增 1,如果不存在这样的 bin,则将其零初始化
  • mH
  • 中的最大频率
  • 初始化空 vector v1, …, vm<
  • 对于每个值 x 都是 H[x] ≥ 0:
    • 对于 i ← 1 到 H[x]:
      • x 附加到 vi

请注意,如果您的 vector 中的对象具有确定它们是否相等的键作为它们的唯一数据成员,则此方法可以正常工作。但是,如果它们有更多状态需要保留但不参与确定相等性,则很容易调整程序以解决这个问题。

  • 初始化一个空直方图H
  • 对于 v 中的每个项目 x:
    • H[key(x)] 加一,如果不存在这样的 bin,则将其零初始化
  • mH
  • 中的最大频率
  • 初始化空 vector v1, …, vm<
  • 对于 v 中的每个值 x:
    • iH[键(x)]
    • x 附加到 vi
    • H[key(x)]减一

如果你想要一个快速的解决方案,你可以使用 std::unordered_map<int, int> 为你的直方图。

这是 C++14 中的(最终有点过度概括的)实现的样子。

#include <algorithm>            // std::max_element
#include <functional>           // std::hash, std::equal_to
#include <iterator>             // std::iterator_traits
#include <unordered_map>        // std::unordered_map
#include <vector>               // std::vector

template<typename FwdIterT,
         typename ValueT = typename std::iterator_traits<FwdIterT>::value_type,
         typename ValueHashT = std::hash<ValueT>,
         typename ValueEqCmpT = std::equal_to<ValueT>>
decltype(auto)
min_partition(const FwdIterT begin, const FwdIterT end)
{
  std::vector<std::vector<ValueT>> partitions {};
  std::unordered_map<ValueT, int, ValueHashT, ValueEqCmpT> histo {};
  for (auto iter = begin; iter != end; ++iter)
    histo[*iter]++;
  const auto cmpfreq = [](const auto& lhs, const auto& rhs){
    return lhs.second < rhs.second;
  };
  const auto maxbin = std::max_element(histo.cbegin(), histo.cend(), cmpfreq);
  partitions.resize(maxbin->second);
  for (auto iter = begin; iter != end; ++iter)
    partitions.at(histo.at(*iter)-- - 1).push_back(*iter);
  return partitions;
}

可以这样使用。

#include <iostream>             // std::cout
#include <string>               // std::string
#include <utility>              // std::begin, std::end

int
main(int argc, char * * argv)
{
  using std::begin;
  using std::end;
  for (int i = 1; i < argc; ++i)
    {
      const std::string text {argv[i]};
      const auto partitions = min_partition(begin(text), end(text));
      std::cout << "input:  " << text << "\n";
      std::cout << "output: " << partitions.size() << " partitions\n\n";
      for (auto it1 = begin(partitions); it1 != end(partitions); ++it1)
        {
          std::cout << "[";
          for (auto it2 = begin(*it1); it2 != end(*it1); ++it2)
            std::cout << (it2 != begin(*it1) ? ", " : "") << *it2;
          std::cout << "]\n";
        }
      if (i != argc - 1)
        std::cout << "\n\n";
    }
}

如果给定一些众所周知的字符串作为输入,它会产生以下输出。

input:  WEWEREARRESTEDAFTERDADATEDEEREGGS
output: 10 partitions

[W, F, A, T, D, R, E, G, S]
[W, S, T, R, A, D, E, G]
[R, T, A, D, E]
[A, R, D, E]
[R, E]
[E]
[E]
[E]
[E]
[E]


input:  ALASDADHADAGLASSSALAD
output: 8 partitions

[H, G, S, L, A, D]
[D, L, S, A]
[L, D, A, S]
[S, D, A]
[A]
[A]
[A]
[A]


input:  THEQUICKBROWNFOXJUMPSOVERTHESLEAZYDOG
output: 4 partitions

[Q, I, C, K, B, W, N, F, X, J, U, M, P, V, R, T, H, S, L, E, A, Z, Y, D, O, G]
[T, H, U, R, S, O, E]
[O, E]
[E, O]

关于c++ - 最小划分对象 vector (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28904178/

相关文章:

c++ - 从文件中读取值、更改值和更新文件

c++ - 如何返回 .dat 文件中的项目索引?

sql - 对现有表进行分区

c# - 如何使用使用不同选项构建的 C# 和 C++ 库创建 Nuget 包?

c++ - 将数据推回二维 vector

hadoop - hive 中的分区和分桶有什么区别?

apache-spark - 为什么过滤器不保留分区?

apache-spark - Spark 知道 DataFrame 的分区键吗?

linux - 主分区的最大数量?

c++ - 基本类型是如何初始化的?