如何在排序链表上应用二进制搜索 O(log n)?

Posted

技术标签:

【中文标题】如何在排序链表上应用二进制搜索 O(log n)?【英文标题】:how to apply binary search O(log n) on a sorted linked list? 【发布时间】:2011-07-13 22:56:18 【问题描述】:

最近我在链表上遇到了一个有趣的问题。给出了排序的单链表,我们必须从这个列表中搜索一个元素。

时间复杂度不应超过O(log n)。这似乎我们需要在这个链表上应用二分查找。如何?由于链表不提供随机访问,如果我们尝试应用二进制搜索算法,它将达到 O(n),因为我们需要找到链表的长度并走到中间。

有什么想法吗?

【问题讨论】:

答案是,如果您需要执行二进制搜索,那么您使用了错误的数据结构。 :) 这不是发明跳过列表的原因吗? 如果还有人对此感兴趣,我想出的 DS 正是这样做的:cs.stackexchange.com/questions/137076/… 【参考方案1】:

是的,可以用java语言如下..

Collections.<T>binarySearch(List<T> list, T key)

对任何List 进行二分搜索。它适用于 ArrayListLinkedList 以及任何其他 List

【讨论】:

List在Collection上下文中的含义很不一样,参考official doc【参考方案2】:

在链表中,二分查找可能无法达到 O(log n) 的复杂度,但至少可以通过使用双指针方法来实现一点点,如本研究工作所述:http://www.ijcsit.com/docs/Volume%205/vol5issue02/ijcsit20140502215.pdf

【讨论】:

链接中论文给出的方法比线性搜索还要糟糕,因为找到中间指针会浪费很多时间。【参考方案3】:

使用 MAPS 创建链接列表。 映射 M , M[第一个元素]=第二个元素 , M[第二个元素]=第三个元素 , ... ... 它是一个链表... 但因为它是一张地图... 它在内部使用二进制搜索来搜索任何元素.. 任何元素的搜索都需要 O(log n)

【讨论】:

显然欺骗了问题和答案......这里没人关心......这个答案有什么问题......你能解释一下Marcin 你要么需要更多时间,要么需要不同的数据结构(Steve Jessop) 我对此投了反对票,因为它难以理解,而且据我所知,它并没有解决问题。 难以理解..如何..它肯定回答了这个问题..用 log n 搜索时间构建的链表......再次......不同的数据结构(史蒂夫杰索普)......类似于这个你可以在 perl 的关联数组中找到链接列表是如何构建的 (a) 过度使用省略号和垂直空间 (b) 您没有完全描述数据结构,但听起来它是所需的单链表。【参考方案4】:

如上所述,这通常是不可能的。但是,在像 C 这样的语言中,如果列表节点是连续分配的,则可以将结构视为节点数组。

显然,这只是对这个问题的一个技巧问题变体的答案,但问题总是一个不可能或一个技巧问题。

【讨论】:

如果节点是连续分配的,那么链表的意义何在? @MarkRansom 给面试题设置者一种优越感?测试可以快速使用怪异、粗糙代码的候选人?毕竟,我确实注意到这是一个技巧问题的技巧答案。 这甚至不是一个技巧答案,就好像您依赖连续存储的元素一样,您放弃了它作为链表的主要优势 - O(1) 插入/删除时间。所以总比用普通数组好,不用管链表。 带有跳过列表的答案是最好的答案,因为:1)它直接回答问题,说单链表是不可能的。 2)它提供了一个明智的选择,尽可能接近所提出的问题。我已经否决了我认为值得投反对票的每个答案,别担心。作为旁注,我想知道最近谁对跳过列表的答案投了反对票 - 这似乎不明智,而令人羡慕。 @BartoszKP 这个答案指出,在一般情况下这是不可能的。你只是喜欢跳过列表。至于“它提供了一个明智的选择,尽可能接近所提出的问题”,这很好,但这不是拒绝不回答您希望提出的问题的答案的理由。【参考方案5】:

使用普通的单链表肯定是不可能的。

草图证明:要检查单链表的最后一个节点,我们必须执行n-1 跟随“下一个”指针的操作[通过归纳证明只有一个引用k+1 th 节点,并且它在kth 节点中,并且需要一个操作来跟随它]。对于某些输入,有必要检查最后一个节点(特别是,如果搜索到的元素等于或大于其值)。因此,对于某些输入,所需时间与n 成正比。

您要么需要更多时间,要么需要不同的数据结构。

请注意,您可以在 O(log n) comparisons 中使用二进制搜索来完成此操作。它只会花费更多的时间,所以这个事实只有在比较比列表遍历更昂贵的情况下才有意义。

【讨论】:

【参考方案6】:

您需要使用skip list。这对于普通链表是不可能的(我真的很想知道这对于普通链表是否可行)。

【讨论】:

跳过列表是使用链表进行二分搜索的解决方案。普通链表是不可能的。 这应该是公认的答案。投票最多的答案要么具有误导性,要么不完整。它只是说“你可能需要别的东西”,这并不是很神奇。这个答案恰到好处。 您不能使用跳过列表。这个问题是关于单链表的。 这个答案清楚地回答了“单链表”的情况。 SkipList 是作为一种合理的替代方案提供的。

以上是关于如何在排序链表上应用二进制搜索 O(log n)?的主要内容,如果未能解决你的问题,请参考以下文章

链表上合并排序的运行时间?

在o(N log N)时间内使用恒定的空间复杂度对链表进行排序

c_cpp 使用常量空间复杂度在O(n log n)时间内对链表进行排序。

排序链表

148.排序链表

148.排序链表