单次遍历中链表的中点?
Posted
技术标签:
【中文标题】单次遍历中链表的中点?【英文标题】:Mid point in a link list in a single traversal? 【发布时间】:2012-08-08 05:00:52 【问题描述】:我试图找到一个单链表的循环开始点。 我想到的是用 2 个指针 *慢,*快,一个以两倍于另一个的速度移动。 如果列表有循环,那么在某个时候
5-6-7-8
| |
1-2-3-4-7-7
慢=快
能否有另一种优雅的解决方案,使列表只遍历一次?
【问题讨论】:
遍历列表,计算节点数,中点=节点数/2四舍五入到最接近的int @peacemaker 你仍然需要遍历列表直到中点。 @peacemaker:这将是一个半遍历。 中点与列表中的循环有什么关系?你想找到循环的开始吗? @peacemaker:当然,您已经找到了中点的索引,但是您必须访问它。在链表的情况下,这意味着再次遍历链表的前半部分。链表的访问时间为 O(n)。 【参考方案1】:您使用两个 walker 的想法,其中一个的速度是另一个的两倍,但是这提出的更基本的问题是您是否选择了合适的数据结构?您应该问自己是否真的需要找到中点,如果需要,还有哪些其他结构可能更适合在 O(1)(恒定)时间内实现这一目标?数组肯定会为集合的中点提供更好的性能,但其他操作速度较慢。在不了解其余上下文的情况下,我无法提出任何其他建议,但我建议您查看您的要求。
【讨论】:
【参考方案2】:我假设这是某种面试问题。
如果您的列表有一个循环,那么要在一次遍历中完成,您需要在快速遍历列表时将节点标记为已访问。当 fast walker 遇到 NULL 或已经访问过的节点时,迭代可以结束,而你的 slow walker 处于中点。
有很多方法可以将节点标记为已访问,但可以使用外部地图或集合。如果直接在节点本身中标记节点,则需要再次遍历以清理标记。
编辑:所以这不是寻找中点,而是在不重新访问已经访问过的节点的情况下进行循环检测。标记也适用于此。只需遍历列表并标记节点。如果你命中 NULL,则没有循环。如果你点击一个访问过的节点,就会出现一个循环。如果标记还包含一个计数器,您甚至可以知道循环从哪里开始。
【讨论】:
关于那个中点问题的另一件事,如果你有偶数节点,会有两个中点,如何找到它们? 你在快步行者移动后移动慢步行者。 fast walker 确定迭代是否继续。因此,对于偶数,中点是慢行者的当前位置和下一个。对于奇数,步行者的当前位置是中点。 假设我们不知道列表的长度,我们必须在一次遍历中完成,然后正如你所说,我们将慢速指针移动到快速指针之后,直到 fast=Null 我们也计算节点数,如果节点=偶数,则慢和慢->如果奇数,则下一个将给出答案,然后慢->下一个是答案...对吗???? @ishansoni:是的,您计算节点数。奇怪的是,答案只是慢,而不是慢->下一个。【参考方案3】:我假设这个单链表以 NULL 结尾。在这种情况下,慢指针和快指针都会起作用。因为快指针的速度是慢指针的两倍,所以如果快指针到达列表末尾,慢指针应该在它的中间。
【讨论】:
以上是关于单次遍历中链表的中点?的主要内容,如果未能解决你的问题,请参考以下文章