这个旧问题 讨论了如何在O(n)时间内对双向链表进行二分查找。该答案中的算法如下:
- 前往列表的中间进行第一次比较。
- 如果与我们要查找的元素相等,则完成。
- 如果大于我们要查找的元素,则向后半程走到开头的一半并重复。
- 如果小于我们要查找的元素,则向前半程走到开头的一半并重复。
这对于双向链表来说完全有效,因为可以向前和向后移动,但是这个算法在单向链表上不起作用。
是否可能使二分查找在单向链表上的时间复杂度为O(n)而不是双向链表?
这个旧问题 讨论了如何在O(n)时间内对双向链表进行二分查找。该答案中的算法如下:
这对于双向链表来说完全有效,因为可以向前和向后移动,但是这个算法在单向链表上不起作用。
是否可能使二分查找在单向链表上的时间复杂度为O(n)而不是双向链表?
这绝对是可行的。实际上,你只需要对双向链表算法做一个改变就可以让它工作。
单向链表的问题在于,如果你有一个指向列表中间的指针,那么你无法倒退回到列表的第一季。但是,如果你仔细想想,你并不需要从中间开始做。相反,你可以从列表的前面开始走路,直到到达第一季。这和之前花费的时间基本相同:你不需要倒退n/4步,而是可以从前面开始,向前走n/4步。
现在假设你已经完成了第一步,在位置n/4或3n/4处。在这种情况下,如果你需要回退到位置n/8或5n/8,你将遇到与之前相同的问题。如果你需要到达位置n/8,那么你可以再次从列表的前面开始,向前走n/8步。那么5n/8呢?这里的诀窍是 - 如果你仍然有指向n/2点的指针,那么你可以从那里开始,向前走n/8步,这将带你到正确的位置。
更普遍地说,不要只存储指向列表中间的指针,而要存储两个指针:一个在值可能出现的范围的前面,一个在该范围的中间。如果你需要前进到列表中的下一个位置,请将指向范围开头的指针更新为指向范围中点,然后将指向范围中点的指针向列表末尾的一半前进一半。如果你需要后退到列表中的上一个位置,请将指向范围中点的指针更新为指向范围开头的指针,然后向前走一半。
总的来说,这与双向链表的时间复杂度完全相同:我们先走n/2步,然后走n/4步,再走n/8步,以此类推,总计O(n)步。我们还只进行O(log n)次比较。唯一的区别是我们需要额外的指针来跟踪。
希望这能帮到您!
O(n)
的时间内完成,也不是它是否有意义。问题是是否以及如何在O(n)
的时间复杂度内完成。 - sepp2k这可以通过使用双指针方法来实现(前提是列表已按排序顺序排列),如在此研究工作中所述:http://www.ijcsit.com/docs/Volume%205/vol5issue02/ijcsit20140502215.pdf