消除 std::vector 中的重复项
eliminating duplicates in std::vector
我有一个非常大的std::vector of std::vectors,其中包含固定数量的无符号整数。
uint 的所有向量都按升序排序。
我目前消除重复向量的方法是
unsigned int i = 0;
while ( i < new_combs.size() )
{
unsigned int j = i + 1;
while ( j < new_combs.size() )
{
unsigned int k = 0;
while ( k < new_combs.at(i).size() && new_combs.at(i).at(k) == new_combs.at(j).at(k) )
++k;
if ( k == new_combs.at(j).size() )
new_combs.erase(new_combs.begin() + j);
else
++j;
}
++i;
}
在这里,new_combs是包含上述向量的向量。
如果向量的向量未排序,是否有更有效的方法来消除重复项?
一个较短的方法是使用 <algorithm>
:
std::sort(new_combs.begin(), new_combs.end());
new_combs.erase(std::unique(new_combs.begin(), new_combs.end()), new_combs.end());
除非你特别需要std::vector
,否则你可以使用std::set
来避免重复。
你有没有考虑过使用 std::set?它是有序的,不允许一开始重复。
如果向量未排序,则无能为力。但是,如果它被排序,您可以使用算法中定义的唯一方法:
new_combs.erase(unique(new_combs.begin(), new_combs.end()), new_combs.end());
渐近地,您的算法看起来像通常的 O(n) 实现,因此是最佳的。(即使我不明白你对i
和j
的对角化策略,以及为什么你只擦除,但从不移动元素。您的代码非常不清楚。但是,您正在复制 STL,唯一循环的较短版本为:
struct unique {
template <class C>
void operator()( C& c ) {
c.erase( std::unique( c.begin(), c.end() ), c.end() );
}
};
std::for_each( new_combs.begin(), new_combs.end(), unique() );
我同意 Luchian Grigorie 的回答,但您也可以考虑将整个外部vector
转换为 unordered_set
,这是一个 O(n) 操作,前提是子向量的哈希不会太不平衡(而不是用于排序的平均 O(n*log(n))。您甚至可以在unordered_set
中使用指向子向量的指针,以避免不必要的复制。对于大量数据,这可能是一个重要的性能差异。
这个例子说明了使用你自己的哈希函数和指针的基本思想(它处理string
的vector
并使用unordered_map
,而不是unordered_set
,但你应该能够相当容易地修改它以满足你的需要)。
您的代码中有几个元素敲响了我对性能的警钟。
首先,您使用的是向量。 从矢量中擦除元素总是很慢。您可以考虑使用不同的容器 (std::list) 或调整您的代码,以便您有一个特殊的值(例如零或 -1)。
其次,您可以使用 std::set 或 std::unordered_set 来保留您已经遇到的值。这样,您只需遍历一次向量。
编辑:忘记这个答案。 我误读了这个问题,认为必须删除重复值(而不是重复向量)。
尽管如此,对所给出的评论的一些反应:
- @Jerry:我同意向量在大多数情况下比列表快,但前提是向量的大小有限。 如果向量包含 100 万个元素,您需要删除第 3 个,然后是第 5 个,然后是第 10 个,...你最终会移动很多元素。 在这种情况下,列表可能会更快。
- @James:在原始问题中,元素不是从向量的末尾删除的,而是从中间删除的。 如果向量非常大(假设有 100 万个元素),那么删除元素仍然可能成为瓶颈。 但是,我同意比使用排序,然后使用唯一排序可能更快。
- 使用std::vector的OpenCL矩阵乘法
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- std::vector的包装器,使数组的结构看起来像结构的数组
- 编译器如何区分std::vector的构造函数
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- 在std::vector上存储带有模板的类实例
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 为什么std::vector比数组慢
- std::vector::迭代器是否可以合法地作为指针
- 如何将二进制格式的 C++ 对象的 std::vector 保存到磁盘?
- 为什么std::vector和std::valarray初始化构造函数不同
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 在没有未定义行为的情况下实现类似std::vector的容器
- 如何调整 std::vector of Eigen::MatrixXd 的大小
- 使用 std::vector::reverse_iterator 将 int 序列化为字节向量?
- 如何将AERT_Allocate与 std:vector 一起使用
- 推导 std::vector::back() 的返回类型
- 如何将原始字节附加到 std::vector?
- std::vector 没有重载函数的实例与参数列表匹配
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?