这个问题在我脑海中挥之不去已有一段时间......
假设我有一个项目列表和一个等价关系,并且比较两个项目需要不变的时间。 我想要返回项目的分区,例如链表的列表,每个链表包含所有等效项。
这样做的一种方法是将等价扩展到项目的排序并对它们进行排序(使用排序算法);那么所有等价物品都会相邻。
但是它可以比排序更有效吗?这个问题的时间复杂度是否低于排序?如果没有,为什么不呢?
答案 0 :(得分:12)
你似乎一口气问两个不同的问题。
1)如果只允许相等检查,它是否比我们有一些排序更容易分区?答案是不。您需要Omega(n ^ 2)比较来确定最坏情况下的分区(例如,所有不同)。
2)如果允许排序,分区是否比排序更容易?答案是否定的。这是因为Element Distinctness Problem。其中说,为了确定所有对象是否都是不同的,您需要进行Omega(nlogn)比较。由于排序可以在O(nlogn)时间内完成(并且还具有Omega(nlogn)下界)并且解决了分区问题,渐近它们同样很难。
如果选择任意哈希函数,则相等的对象不需要具有相同的哈希值,在这种情况下,通过将它们放在哈希表中,您没有做任何有用的工作。
即使你确实提出了这样的哈希(相同的对象保证具有相同的哈希值),时间复杂度预期 O(n)表示良好的哈希值,最坏的情况是Omega( N ^ 2)。
是否完全使用散列或排序取决于问题中不可用的其他约束。
其他答案似乎也忘记了(主要)关于比较分区和排序的问题!
答案 1 :(得分:6)
如果您可以为项目定义哈希函数以及等价关系,那么您应该能够在线性时间内进行分区 - 假设计算哈希是恒定时间。哈希函数必须将等效项映射到相同的哈希值。
如果没有哈希函数,则必须将要插入分区列表的每个新项目与每个现有列表的头部进行比较。该策略的效率取决于最终将有多少分区。
假设您有100个项目,最终将它们划分为3个列表。然后,在将其插入其中一个列表之前,必须将每个项目与最多3个其他项目进行比较。
然而,如果这100个项目最终将被划分为90个列表(即,很少有等价物品),那么这是一个不同的故事。现在你的运行时更接近二次而不是线性。
答案 2 :(得分:3)
如果您不关心等价集的最终排序,那么划分为等价集可能会更快。但是,它取决于算法和每组中的元素数量。
如果每组中的项目非常少,那么您也可以对元素进行排序,然后找到相邻的相等元素。一个好的排序算法是n个元素的O(n log n)。
如果每个元素中都有大量元素,那么您可以获取每个元素,并与现有集合进行比较。如果它属于其中一个,则添加它,否则创建一个新集。这将是O(n * m),其中n是元素的数量,m是等价集的数量,对于大的n和小的m小于O(n log n),但是当m倾向于n时更差
组合排序/分区算法可能会更快。
答案 3 :(得分:2)
基于比较的排序通常具有O(n log n)的下限。
假设您迭代您的项目集并将它们放入具有相同比较值的项目的桶中,例如在一组列表中(例如使用哈希集)。即使在从集合中检索列表列表之后,此操作显然也是O(n)。
--- 编辑: ---
这当然需要两个假设:
因此,分区的下限是O(n)。
答案 4 :(得分:2)
如果必须使用比较器,则下限为Ω(n log n)比较,用于排序或分区。原因是必须检查所有元素Ω(n),并且比较器必须对每个元素执行log n比较,以唯一地标识或放置该元素相对于其他元素(每个比较将空间划分为2,因此对于空间大小为n,需要进行log n比较。)
如果每个元素都可以与在恒定时间内导出的唯一键相关联,则下限为Ω(n),用于对ant分区进行排序(c.f。RadixSort)
答案 5 :(得分:1)
通常,分区比排序更快,因为您不必将每个元素与每个可能等效的已排序元素进行比较,您只需将它与已经建立的分区键进行比较。仔细看看radix sort。基数排序的第一步是根据密钥的某些部分对输入进行分区。基数排序为O(kN)。如果您的数据集具有以给定长度k为界的键,则可以对其进行基数排序O(n)。如果您的数据具有可比性并且没有有界密钥,但是您选择了一个有界密钥来对该集合进行分区,则对该集合进行排序的复杂性将为O(n log n),并且分区将为O(n)
答案 6 :(得分:1)
这是数据结构中的经典问题,是的,它比排序更容易。如果您还希望能够快速查找每个元素所属的集合,那么您需要的是不相交的集合数据结构以及union-find操作。见这里:http://en.wikipedia.org/wiki/Disjoint-set_data_structure
答案 7 :(得分:0)
使用散列函数执行可能不完美的分区所需的时间将是O(n + bucketcount)[not O(n * bucketcount)]。使桶数足够大以避免所有冲突将是昂贵的,但是如果散列函数很好地工作,则每个桶中应该存在少量不同的值。如果一个人可以很容易地生成多个统计独立的散列函数,那么可以使用其键不与第一个匹配的每个桶,并使用另一个散列函数来对该桶的内容进行分区。
假设每个步骤的桶数量恒定,则时间将为O(NlgN),但如果将桶数设置为sqrt(N),则平均通过次数应为O(1 )和每次通过O(n)的工作。