计算排序向量的向量中唯一值的计数
Compute the count of unique values in vector of sorted vectors
我有一个类型为std::vector<std::vector<size_t>>
的对象,称为v
,其中对每个子向量(每个std::vector<size_t>
(进行排序。我想计算v
的每个唯一size_t
被找到的次数。我在考虑使用std::map<size_t, size_t>
,做一些类似的事情
int main()
{
const std::vector<std::vector<size_t>> v = {
{4, 10, 12, 18, 20, 28, 34},
{4, 12, 18, 20, 28},
{4, 17, 18, 20, 28},
{4, 17, 18, 20, 28, 37}
};
std::map<size_t, size_t> counts;
for (const auto& a : v)
{
for (const auto& b : a)
{
auto it = counts.lower_bound(b);
if (it != counts.end() && !(counts.key_comp()(b, it->first)))
{
// mut already exist
++(it->second);
} else
{
// mut is new
counts.insert(it, std::map<size_t, size_t>::value_type(b, 1));
}
}
}
for (auto it = counts.begin() ; it != counts.end() ; ++it)
std::cout << it->first << ": " << it->second << "n";
}
,输出
4: 4
10: 1
12: 2
17: 2
18: 4
20: 4
28: 4
34: 1
37: 1
正如预期的那样。
在实践中,这些值在0和4e9之间均匀分布,因此促使我使用std::map
而不是std::vector
。如果一个值存在于一个向量中,则增加了在连续向量中一次又一次地找到该值的可能性,因此与已经插入的值的增加相比,插入相对较少。此外,向量的子部分往往是相同的。
有更好的技术吗?例如,当计算lower_bound
时,在对元素进行排序时,使用前一个元素的插入点会更快。类似
for (const auto& a : v)
{
MapType::iterator it = a.begin();
for (const auto& b : a)
{
auto it = counts.lower_bound(it, b); // Use `it` to avoid searching in elements that precedes its position
// etc..
}
}
,但是我不认为std::map::lower_bound可以使用from
迭代器。
我提出了一种重用插入点的方法。我使用的事实是,插入是罕见的。
我会使用成对的排序向量作为MapType。
typedef std::vector<std::pair<size_t, size_t>> MapType;
假设向量是根据key_comp
函子排序的。然后可以为MapType构建一个Compare函子(这里我使用的是lambda表达式(。
auto comp = [&](std::pair<size_t, size_t>& p1, std::pair<size_t, size_t> const& p2)
{
return key_comp(p1.first,p2.first);
};
现在,对于v
中的每个向量,您可以重用过去的插入点,因为您知道元素是排序的。
这是的完整代码
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
typedef std::vector<std::pair<size_t, size_t>> MapType;
int main()
{
const std::vector<std::vector<size_t>> v = {
{4, 10, 12, 18, 20, 28, 34},
{4, 12, 18, 20, 28},
{4, 17, 18, 20, 28},
{4, 17, 18, 20, 28, 37}
};
auto key_comp = [](std::size_t v1, std::size_t v2) {
return v1 < v2;
};
auto comp = [&](std::pair<size_t, size_t>& p1, std::pair<size_t, size_t> const& p2)
{
return key_comp(p1.first,p2.first);
};
MapType counts;
for (const auto& a : v)
{
auto it = counts.begin();
for (const auto& b : a)
{
// You can start from it instead of counts.begin() because vector a is sorted
it = std::lower_bound(it, counts.end(), MapType::value_type(b, 1), comp);
if (it != counts.end() && !(key_comp(b, it->first)))
{
// mut already exist
++(it->second);
} else
{
// mut is new
// Insertion may invalidate iterators so you need to reassign it
it = counts.insert(it, MapType::value_type(b, 1));
}
}
}
for (auto it = counts.begin() ; it != counts.end() ; ++it)
std::cout << it->first << ": " << it->second << "n";
}
输出:
4: 4
10: 1
12: 2
17: 2
18: 4
20: 4
28: 4
34: 1
37: 1
编译器资源管理器链接:https://godbolt.org/z/zoY7KG
这需要进行性能测试,但假设矢量的数量明显小于矢量中的数字,则此方法可能工作得更快:
using szvec = std::vector<size_t>;
using range = std::pair<szvec::const_iterator,szvec::const_iterator>;
const std::vector<szvec> v = {
{4, 10, 12, 18, 20, 28, 34},
{4, 12, 18, 20, 28},
{4, 17, 18, 20, 28},
{4, 17, 18, 20, 28, 37}
};
// we use greater so iterator with smallest value will be on top of queue
auto sort_range = []( const range &r1, const range &r2 ) {
return *(r1.first) > *(r2.first);
};
std::priority_queue<range,std::vector<range>,decltype(sort_range)> q( sort_range );
// we assume all vectors are not empty on start
// otherwise we need to check for empty range before pushing
for( const auto &vec : v ) q.push( std::make_pair( vec.cbegin(), vec.cend() ) );
std::vector<std::pair<size_t,size_t>> counters;
while( !q.empty() ) {
auto r = q.top();
q.pop();
if( counters.empty() || counters.back().first != *(r.first) )
counters.emplace_back( *(r.first), 1 );
else
counters.back().second++;
if( ++r.first != r.second ) q.push( r );
}
for( const auto &p : counters )
std::cout << p.first << ":" << p.second << std::endl;
所以,我们的想法是让不同向量的迭代器按照它们所指向的值进行排序,并对通过迭代器传递的相同值进行计数,而不是单独处理每个向量。
实例
相关文章:
- 计算排序向量的向量中唯一值的计数
- C++ 中的特征向量计算
- 对对应于矩阵的行和列的对向量进行排序
- 使用模板化分配器和对向量进行排序的函数
- C++对结构向量进行排序
- 在C++中对结构向量进行排序时出现问题
- 如何在 c++ 中对 3 对向量进行排序
- 对没有比较器或λ函数的向量进行排序?
- 使用指针指向对象C++对向量进行排序
- 如何根据第二列/第三列等对字符串向量进行排序?
- 根据组件 1、2(和 3)对空间 (2D/3D) 向量进行排序
- 按类成员的顺序对包含类对象的C++向量进行排序
- 有没有办法根据用户对向量进行排序?
- 同步对多个向量进行排序
- 如何对向量进行排序<浮点数,字符串>而不考虑字符串
- 基于不同字段的对象向量的排序功能
- 尝试使用比较运算符对对象向量进行排序
- 根据类外的值对向量进行排序
- 对坐标结构的向量进行排序
- STL按客户"<"运算符对向量进行排序。为什么要将"<"运算符定义为 const?