链表
链表是按线性单向顺序排列的值的集合
与数组对比,链表的优势是插入和删除时间复杂度都是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
网友评论