我想迭代排序列表以获取不同数字的数量。
请在下面找到我的尝试。列表的大小为k*k
。
在对列表进行排序时,我会比较连续项以识别重复项。
int count_distinct(list<int> v)
{
int num = k*k;
std::list<int>::iterator it;
it = v.begin();
for (int a=0; a<k*k-1; a++)
{
if(*it == *it+1)
num--;
it++;
}
return num;
}
我无法更改列表,因此std::list::unique()
不是一个选项。复制列表或唯一项目对我来说太慢了。
答案 0 :(得分:2)
如何使用std::set
来获取唯一元素数?
size_t count_distinct(const list<int>& v)
{
std::set<int> temp (v.begin(), v.end());
return temp.size();
}
答案 1 :(得分:2)
假设您要查找该列表中唯一整数的数量,并且列表未排序,您可以使用临时集或unordered_set,如下所示:
size_t count_distinct(list<int> v)
{
std::unordered_set<int> distinct;
for(auto &x : v)
{
distinct.insert(x);
}
return distinct.size();
}
答案 2 :(得分:2)
以下是用于提取所有唯一值的容器的解决方案 (因为你之前说过想要使用它们):
计算唯一值的方法:
template < typename T >
size_t count_unique(const std::list<T> & input)
{
std::set<T> unique(input.begin(), input.end());
return unique.size();
}
提取唯一值列表的方法:
template < typename T >
void unique(const std::list<T> & input, std::list<T> & output)
{
std::set<T> unique(input.begin(), input.end());
std::copy(unique.begin(), unique.end(), std::back_inserter(output));
}
示例程序:
int main(int argc, char** argv)
{
std::list<int> list = { 1, 3, 4, 10, 3, 1, 6, 7 };
std::list<int> out;
std::cout << count_unique(list) << std::endl;
unique(list, out);
for (auto & x : out)
std::cout << x << std::endl;
}
答案 3 :(得分:2)
您的代码存在以下问题:
*it == *it+1
始终为假(您比较n
和n+1
)。可能你想写*it == *(it+1)
但std::list
有bidirectional iterators而你不能+1
。 代码应该是这样的:
size_t count_distinct(const std::list<int>& l) {
if (l.empty()) return 0;
size_t distinct = l.size();
auto prev = l.begin();
for (auto cur = std::next(prev); cur != l.end(); ++cur, ++prev) {
if (*cur == *prev)
--distinct;
}
return distinct;
}
或者您可以编写std::unique
算法的修改版本:
template<class ForwardIt>
size_t unique_cnt(ForwardIt first, ForwardIt last) {
if (first == last)
return 0;
size_t distinct = 1;
ForwardIt prev = first;
while (++first != last) {
if (!(*prev == *first)) {
++distinct;
}
prev = first;
}
return distinct;
}
然后简单地使用它
size_t distinct = unique_cnt(l.begin(), l.end());
还有std::unique_copy
+自定义迭代器方法,但它看起来不够优雅。
答案 4 :(得分:1)
对于排序数据,您可能不会比您尝试实施的直接方法更有效。
我更喜欢有类似的东西,因为我发现它更直观地向上计数而不是向下计数:
circles[i].y = circles[i].y > canvas.height ? 0 : circles[i].y + 1;
您还可以通过提供自定义OutputIterator来使std::unique_copy()
算法计数而不是复制。但与上述方法相比,这在性能上几乎没有什么好处。当C ++ 17中的parallel implementations算法可用时,也许值得重新审视。
以下是一个例子:
std::size_t count_unique_sorted(std::list<int> const& l) {
if (l.empty()) return 0;
std::size_t count = 1;
auto previous_value = l.front();
// TODO: hope that the compiler fixes that redundant first comparison...
for (auto next_value : l) {
if (next_value != previous_value) {
// the value changed! increment count and update previous_value
++count;
previous_value = next_value;
}
}
return count;
}
请注意,在这两种情况下,您都希望将列表作为const引用传递,而不是作为副本传递给函数。
如果您觉得这仍然很慢,请随意探索并行化的乐趣。这样做的好处可能取决于数据量和分布。所以你应该在那时开始一些系统的分析。
除非您需要对这些值进行重新排序,否则请考虑首先将数据转储到template <typename T>
struct counter : public std::iterator<std::output_iterator_tag, T> {
explicit counter(std::size_t& count) : count(count) {}
counter& operator*() { return *this; }
counter& operator++() { return *this; }
void operator=(T const&) { ++count; }
private:
std::size_t& count;
};
std::size_t count_unique_sorted2(std::list<int> const& l) {
std::size_t count = 0;
std::unique_copy(l.begin(), l.end(), counter<int>(count));
return count;
}
。拥有随机访问迭代器简化了事情,拥有更好的局部性也可以加快速度......
答案 5 :(得分:0)
您可以使用std::list<int>::unique()
获取v
和size()
中的所有不同元素来计算它们。必须对v
进行排序。检查是否使用函数std :: is_sorted()对v
进行了排序。如果不是 - 对它进行排序。这也意味着count_distinct
不适用于const列表对象。
size_t count_distinct(list<int>& v)
{
if (!is_sorted(v.begin(), v.end()))
{
v.sort();
}
v.unique();
return v.size();
}