【问题标题】:How to detect a loop/cycle in a linked list using Swift [duplicate]如何使用 Swift 检测链表中的循环/循环 [重复]
【发布时间】:2020-01-06 09:58:39
【问题描述】:

我正在尝试使用 Swift 在链表中检测循环/循环的函数。 有人可以告诉我代码如何做到这一点吗? 我在其他一些我不太熟悉的编程语言中找到的唯一答案

这是我目前正在编写的代码。

public class Node<Value> {

    public var value: Value
    public var next: Node?

    public init(value: Value, next: Node? = nil) {
        self.value = value
        self.next = next
    }
}

public struct LinkedList<Value> {

    public var head: Node<Value>?
    public var tail: Node<Value>?

    public init() {}

    public var isEmpty: Bool {
        return head == nil
    }

    public mutating func push(_ value: Value) {
        head = Node(value: value, next: head)
        if tail == nil {
            tail = head
        }
    }

    public mutating func apped(_ value: Value) {

        guard !isEmpty else {
            push(value)
            return
        }
        tail!.next = Node(value: value)

        tail = tail!.next
    }
}

extension Node: CustomStringConvertible {

    public var description: String {
        guard let next = next else {
            return "\(value)"
        }

        return "\(value) -> "  + String(describing: next) + " "
    }
}

extension LinkedList: CustomStringConvertible {

    public var description: String {
        guard let head = head else {
            return "Empty List"
        }
        return String(describing: head)
    }
}

【问题讨论】:

  • 看看this Floyd 算法的实现(Scott Hunter 在下面提到)。它不是很快,但你应该能够轻松地移植它。
  • 没有理由将此问题标记为重复,因为它显然不是!正如我所说的其他编程语言的答案,但我不熟悉它们。那么有人可以帮助我如何在 Swift 中做到这一点吗?
  • 弗洛伊德算法的哪些部分您需要帮助?你试过什么?
  • 链接到的问题与语言无关,答案解释了算法(带有指向更多文档的链接)。这些示例是用 Java 等编写的,但是一旦你理解了 idea,它应该很容易在 Swift 中实现。

标签: swift algorithm data-structures linked-list


【解决方案1】:

一种方法是遍历列表,以某种方式跟踪先前访问过的节点;最终,您要么访问之前访问过的节点(因此知道存在循环),要么到达终点(并且知道没有)。

一种更聪明的方法是使用 2 个指针遍历列表,但其中一个指针的移动速度是另一个指针的两倍。如果存在循环,则在某个点上,较快的指针将赶上循环中较慢的指针,因此无需明确跟踪以前访问过的节点。

【讨论】:

  • 如果我是对的,对于奇数长度的循环(或者是偶数?),指针可能会相互错过。所以可能需要比较当前指针和下一个指针。
  • 谢谢,斯科特你帮了我很多
  • 基本上,这就是答案: public mutating func containsCycle(firstNode: Node) -> Bool { var slowRunner = firstNode var fastRunner = firstNode while let nextSlowRunner = slowRunner.next,让 nextFastRunner = fastRunner.next?.next { slowRunner = nextSlowRunner fastRunner = nextFastRunner if fastRunner === slowRunner { return true } } return false } }
  • 或者,用英文:不要把 fast 指针看作是 skipping 一个节点,而是遍历(和 checking i>) slow 指针每 1 个节点 2 个节点。
  • @yves:不。你先慢点。快速跳过慢速的唯一方法是,如果它在双倍递增之前正好落后于慢速。但由于先移动慢,这意味着快和慢在慢增加之前处于同一点,并且已经检测到了。
猜你喜欢
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 2011-12-04
  • 2012-01-06
  • 1970-01-01
相关资源
最近更新 更多