美文网首页
Swift 5.3 数据结构——链表 LinkedList

Swift 5.3 数据结构——链表 LinkedList

作者: Sunooo | 来源:发表于2020-10-18 12:36 被阅读0次

    链表

    链表是按线性单向顺序排列的值的集合
    与数组对比,链表的优势是插入和删除时间复杂度都是O(1)

    链表由一系列的节点Node组成,一个节点有两个部分,一部分保存一个数据,另一部分保存下一个节点

    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
        }
    }
    
    extension Node: CustomStringConvertible {
        public var description: String {
            guard let next = next else {
                return "\(value)"
            }
            return "\(value)=>" + String(describing: next)
        }
    }
    

    一个链表中会保存头结点和尾结点。

    public struct LinkedList<Value> {
        public var head: Node<Value>?
        public var tail: Node<Value>?
        
        public init() {}
        
        public var isEmpty: Bool {
            head == nil
        }
    }
    

    双向链表中的节点Node还会保存前一个Node

    public class Node<T> {
        public var value: T
        public var next: Node<T>?
        public var previous: Node<T>?
        
        public init(value: T) {
            self.value = value
        }
    }
    

    链表一般会包含一下常用的增删改查方法
    push 在头部增加一个node
    append 在尾部增加一个node
    insert 插入一个node
    node at index 查询一个node
    pop 移除头部的一个node
    removeLast 移除尾部的一个node
    remove after 移除某个node之后的一个node

    extension LinkedList {
        public mutating func push(_ value: Value) {
            copyNodes()
            head = Node(value: value, next: head)
            if tail == nil {
                tail = head
            }
        }
        
        public mutating func append(_ value: Value) {
            copyNodes()
            guard !isEmpty else {
                push(value)
                return
            }
            
            tail!.next = Node(value: value)
            
            tail = tail?.next
        }
        
        @discardableResult
        public mutating func insert(_ value: Value, after node: Node<Value>) -> Node<Value> {
            copyNodes()
            guard tail !== node else {
                append(value)
                return tail!
            }
            node.next = Node(value: value, next: node.next!)
            return node.next!
        }
        
        
        public func node(at index: Int) -> Node<Value>? {
            var currentNode = head
            var currentIndex = 0
            
            while currentNode != nil && currentIndex < index {
                currentNode = currentNode!.next
                currentIndex += 1
            }
            
            return currentNode
        }
    }
    
    extension LinkedList {
        @discardableResult
        public mutating func pop() -> Value? {
            copyNodes()
            
            defer {
                head = head?.next
                if isEmpty {
                    tail = nil
                }
            }
            
            return head?.value
        }
        
        @discardableResult
        public mutating func removeLast() -> Value? {
            copyNodes()
            guard let head = head else {
                return nil
            }
            
            guard head.next != nil else {
                return pop()
            }
            
            var prev = head
            var current = head
            
            while let next = current.next {
                prev = current
                current = next
            }
            
            prev.next = nil
            tail = prev
            return current.value
        }
        
        @discardableResult
        public mutating func remove(after node: Node<Value>) -> Value? {
            
            guard let node = copyNodes(returningCopyOf: node) else {
                return nil
            }
            defer {
                if node.next === tail {
                    tail = node
                }
                node.next = node.next?.next
            }
            
            return node.next?.value
        }
    }
    

    因为上面的链表是struct类型,但是节点是class类型,因此在链表直接赋值传递的时候,新链表中的节点跟旧链表中的节点在内存中是一个地址,更改新链表的数据,就会影响旧链表。
    这时候需要引入一个COW(copy and write),顾名思义,就是每次操作链表之前先进行一次copy,然后再执行相应的操作,这样每次操作完获得的链表都是新的,里面的节点也都是新的,旧链表会自动释放的。

     private mutating func copyNodes(returningCopyOf node: Node<Value>?) -> Node<Value>? {
            guard !isKnownUniquelyReferenced(&head) else {
                return nil
            }
            guard var oldNode = head else {
                return nil
            }
            
            head = Node(value: oldNode.value)
            var newNode = head
            var nodeCopy: Node<Value>?
            
            while let nextOldNode = oldNode.next {
                if oldNode === node {
                    nodeCopy = newNode
                }
                newNode!.next = Node(value: nextOldNode.value)
                newNode = newNode!.next
                
                oldNode = nextOldNode
            }
            
            return nodeCopy
        }
    

    github仓库地址 https://github.com/SunZhiC/DataStructuresInSwift

    References

    Data Structures & Algorithms in Swift by Matthijs Hollemans.
    https://github.com/apple/swift-algorithms
    https://github.com/raywenderlich/swift-algorithm-club

    相关文章

      网友评论

          本文标题:Swift 5.3 数据结构——链表 LinkedList

          本文链接:https://www.haomeiwen.com/subject/lkzqmktx.html