如何检查一个元素是否在std::set中?
在C++的STL中,像std::vector、std::list和std::set这样的容器类型中,没有像contains()这样的成员函数。这是因为这样的方法会导致编写低效的代码。这样的方法可能只是在内部执行this->find(key) != this->end(),但是考虑一下当key确实存在时你要做什么;在大多数情况下,你可能会想要获取元素并对其进行操作。这意味着你需要进行第二次查找,这是低效的。最好直接使用find,这样你就可以缓存结果,像这样:
auto it = myContainer.find(key); if (it != myContainer.end()) { // Do something with it, no more lookup needed. } else { // Key was not present. }
当然,如果你不关心效率,你可以自己编写一个,但在这种情况下,你可能不应该使用C++... 😉
那么对于set呢?通常你已经有了元素,只是想检查它是否存在。有没有参考说明这是否是STL中没有包含这样一个方法/函数的真正原因,还是你的猜测呢?这是我的猜测。确实,对于std::set来说,这可能只是为了一致性。一致性并不是STL的强项...(list::remove,remove(只对vector有意义)等...)。
我完全不同意,std::remove算法适用于任何类似STL的容器,但它不会直接删除元素(因为它不知道容器的内部结构,即std::list与std::vector不同)。这就是为什么会使用成员erase(对于forward_list是erase_after)与std::remove结合使用的原因。关联容器为了提高效率定义了它们自己版本的一些算法(如remove,find等):例如,在list中,你只需要重新链接内部指针,而不需要执行通用的remove算法。
它似乎有点奇怪,但它确实可行。但这是没有意义的。例如,试着在list或slist上使用它。结果会是什么?这是可取的吗?
我的观点仍然成立。只有一些容器有remove成员。一致性并不是STL的强项...
我同意一些容器引入特定于算法的成员函数(因为算法与容器解耦,不知道它们的结构,因此只能通过迭代器进行访问),我同意这可能是不一致的,然而std::algorithms适用于所有容器(对迭代器有限制,不能对非随机迭代器使用sort)。在list上的std::remove可以工作,它在std::vector上所做的事情也一样,基本上是移动end迭代器。你有奇怪行为的例子吗?
当std::remove(a_list.begin(), a_list.end())
有用吗?它对链接列表有什么实际影响?
也许我没有理解你的意思,对于来回的评论表示抱歉。这是一个在线代码,比较了std::vector和std::list的std::remove,我认为在这两种情况下它的行为是相同的ideone.com/Psbepy
对我来说,不包含一个功能因为有人可能会错误地使用它而没有包括它,这是没有意义的。编程是给那些能够独立思考并对他们的代码及其性能负责的人。
请注意,C++20引入了contains()。实际上有很多原因你可能想要检查一个元素是否在一个集合中,而不需要事先获取一个迭代器。实际上,对于一个集合,你不能对这个迭代器做太多事情,除了删除元素,而删除元素你可以在没有先前查找的情况下做到。
我不同意在大多数情况下你会想要对元素做些什么。对于集合,检查一个值是否存在是非常常见的。对于映射,更有可能你会想要相应的值。
这个回答没有意义。没有contains()是因为STL设计不好,过分强调统一的接口而不是可用性。C++20修复了这个问题。请注意,清晰的源代码和明确的语义也有助于效率。
胡说八道。这个问题是关于std::set的,而在这种情况下,没有与键关联的元素。
如何检查一个元素是否在std::set中?
问题的出现原因:
大多数情况下,我需要在检查元素是否存在的同时访问该元素。因此,我仍然需要找到迭代器。然后,当然,最好将其与end
进行比较。
解决方法:
在C++20中,set有一个contains
函数,所以可以使用以下方法来检查元素是否存在:
if (myset.contains(x)) { // x is in the set } else { // no x }
该方法也适用于multiset
和multimap
。另外,std::set通常使用有序树结构实现,因此count()
和find()
的时间复杂度都为O(logn),它们都不会遍历集合中的所有元素。
另一个支持find()
的论点是:如果容器类型发生改变,那么使用count()
的所有代码都需要修复,而使用find()
的代码仍然可以正常工作。
此外,在GCC中,对于set
,count()
实际上使用了find()
。
通过使用contains()
函数(在C++20中可用)或find()
函数,可以检查元素是否在std::set中。其中contains()
函数更加直观和自说明,而find()
函数更加灵活和具有可扩展性。
在C++20之前,要检查元素是否在std::set中,通常的方式是使用find()函数:
const bool is_in = container.find(element) != container.end();
然而,这种方式只适用于set和map,对于vector、list等容器是没有find()成员函数的。
对于vector和list,我们可以使用std::find()来检查元素的存在:
std::find(container.begin(), container.end(), element) != container.end();
但是,这种方式的时间复杂度为O(N),效率较低。
因此,更好的方式是使用count()函数,因为它更简洁,并且将结果转换为bool类型:
const bool is_in = container.count(element) != 0;
另外,需要注意的是,count()函数的实现实际上是调用了find()函数,返回值为0或1:
return _M_t.find(__x) == _M_t.end() ? 0 : 1;
不过需要强调的是,count()函数的效率较低,因为它需要遍历整个数据结构。而find()函数在找到元素后就会停止搜索。
从C++20开始,我们可以使用contains()函数来检查元素是否在容器中,例如std::set:
const bool is_in = container.contains(element);
这种方式更加简洁和直观。
总结起来,以前的方式是使用find()函数来检查元素是否在std::set中,对于vector和list则使用std::find()函数。然而,这些方式的效率并不高。从C++20开始,我们可以使用contains()函数来检查元素是否存在于容器中,这种方式更加简单和直观。