我怎样才能用另一种语言(也许C++)实现Python集

How can I implement Python sets in another language (maybe C++)?

本文关键字:C++ 也许 实现 Python 语言 另一种      更新时间:2023-10-16

我想将一些我已经编写的Python代码翻译成C++或其他快速语言,因为Python的速度不够快,无法完成我想做的事情。然而,有问题的代码滥用了 Python 集的一些令人印象深刻的功能,特别是我在性能关键循环中发送垃圾邮件的平均 O(1) 成员资格测试,我不确定如何在另一种语言中实现 Python 集。

在 Python 的时间复杂度 Wiki 页面中,它指出集合平均具有 O(1) 成员测试,在最坏情况下为 O(n)。我使用 timeit 亲自对此进行了测试,并对 Python 集进行成员资格测试的速度如此之快感到惊讶,即使是大 N。我查看了这个 Stack Overflow 答案,看看C++集合在使用find操作时如何比较,以查看元素是否是给定集合的成员,它说它是 O(log(n))。

我假设find的时间复杂度是对数的,因为C++ std 库集是用某种二叉树实现的。我认为因为 Python 集具有平均 O(1) 成员资格测试和最坏情况 O(n),它们可能是使用某种带有存储桶的关联数组实现的,这些数组可以轻松查找元素并测试它的一些虚拟值,这表明该元素不是集合的一部分。

问题是,我不想通过切换到另一种语言来减慢代码的任何部分(因为这是我首先试图解决的问题),那么我如何实现我自己的 Python 集版本(特别是只是快速成员资格测试)在另一种语言中?有没有人知道Python集是如何实现的,如果没有,谁能给我任何一般提示来指出我正确的方向?

不是在寻找源代码,只是在寻找有助于我入门的一般想法和链接。

我对关联数组做了一些研究,我想我理解它们实现背后的基本思想,但我不确定它们的内存使用情况。如果 Python 集确实只是真正的关联数组,我如何在最少的内存使用下实现它们?

附加说明:我想要使用的相关集合将最多包含 50,000 个元素,并且集合的每个元素都将在很大的范围内(例如 [-999999999, 999999999])。

  1. O(1)O(log n)之间的理论差异在实践中意义不大,尤其是在比较两种不同的语言时。 对于n的大多数实用值来说,log n很小。每个实现的常量因子显然更为重要。
  2. C++11 现在已经unordered_setunordered_map。即使不能使用 C++11,也总是有 Boost 版本和 tr1 版本(后者命名为 hash_* 而不是 unordered_* )。

几点:正如已经指出的那样,你有std::setstd::unordered_set(后者仅在 C++11 中,但大多数编译器都有多年来提供了类似的东西作为扩展)。 这首先是由某种平衡树(通常是红黑)实现的树),第二个作为hash_table。 哪一个更快取决于数据类型:第一种需要某种排序关系(例如 <是否在类型上定义了它,但您可以定义自己的);这第二个等价关系(例如==)和一个哈希与此等价关系兼容的函数。 首先是O(lg n),第二个O(1),如果你有一个好的哈希函数。 因此:

  • 如果顺序比较明显快于哈希, std::set实际上可能更快,至少对于"较小"的数据集,其中"更小"取决于差异有多大 - 对于字符串,例如,比较通常会在第一个之后解决几个字符,而哈希代码将查看每个字符。 在我做的一个实验中(很多年前),用字符串30-50个字符,我发现盈亏平衡点约为100000元素。

  • 对于某些数据类型,只需找到一个好的哈希函数,即与类型兼容可能很困难。 Python 使用哈希表来它的集合,如果您使用函数定义一个类型,则始终__hash__返回 1,它将非常非常慢。 编写一个好的哈希函数并不总是显而易见的。

  • 最后,两者都是基于节点的容器,这意味着它们使用了很多比例如更多的内存 std::vector,地方性很差。 如果查找是主要操作,您可能需要考虑std::vector,保持排序并使用std::lower_bound进行查找。根据类型,这可能会导致显着的加速,并且更少的内存使用。