swift实现单链表

161 阅读3分钟

链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的。

首先定义一个节点:

class Node<T> {
    // 节点内容
    var element: T?
    // next节点
    var next: Node<T>?
    
    init(element: T? = nil, next: Node<T>? = nil) {
        self.element = element
        self.next = next
    }
}
    

下面为链表实现代码,提供了添加、删除、清空、设置、获取方法供外界使用。

class SingleLinkedList<T: Equatable> {
    // 链表长度
    var size: Int = 0
    // 头节点
    var head: Node<T>?
    
    // MARK: 清空
    func clear() {
        size = 0
        head = nil
    }
    
    // MARK: 获取index位置对应节点对象
    func get(_ index: Int) -> T? {
        // 最好:O(1) 最坏:O(n) 平均:O(n)
        return node(index)?.element
    }
    
    // MARK: 设置index位置对应节点对象
    @discardableResult
    func set(_ index: Int, _ element: T) -> T? {
        // 最好:O(1) 最坏:O(n) 平均:O(n)
        let node = node(index)
        let old = node?.element
        node?.element = element
        return old
    }
    
    // MARK: 在末尾位置添加节点对象
    func add(_ element: T) {
        add(size, element)
    }
    
    // MARK: 在index位置添加节点对象
    func add(_ index: Int, _ element: T) {
        // 最好:O(1) 最坏:O(n) 平均:O(n)
        if !rangeCheckForAdd(index) {
            return
        }
        
        if index == 0 {
            head = Node(element: element, next: head)
        } else {
            let prev = node(index - 1)
            prev?.next = Node(element: element, next: prev?.next)
        }
        size += 1
    }
    
    // MARK: 删除index位置对应节点对象
    @discardableResult
    func remove(_ index: Int) -> T? {
        // 最好:O(1) 最坏:O(n) 平均:O(n)
        if !rangeCheck(index) {
            return nil
        }
        var current = head
        if index == 0 {
            head = head?.next
        } else {
            let prev = node(index - 1)
            current = prev?.next
            prev?.next = current?.next
        }
        size -= 1
        return current?.element
    }
    
    // MARK: 获取节点对象所在位置
    @discardableResult
    func indexOf(_ element: T) -> Int {
        var current = head
        for i in 0..<size {
            if element == current!.element {
                return i
            }
            current = current?.next
        }
        return -1
    }
    
    // MARK: 获取index位置对应的节点对象
    @discardableResult
    private func node(_ index: Int) -> Node<T>? {
        if !rangeCheck(index) {
            return nil
        }
        var node = head
        for _ in 0..<index {
            node = node?.next
        }
        return node
    }
    
    private func rangeCheck(_ index: Int) -> Bool {
        let enable = index >= 0 && index < size
        if !enable {
            print("### ERROR ### \(index) out of bounds. size = \(size)")
        }
        return enable
    }
    
    private func rangeCheckForAdd(_ index: Int) -> Bool {
        let enable = index >= 0 && index <= size
        if !enable {
            print("### ERROR ### \(index) out of bounds. size = \(size)")
        }
        return enable
    }
}

下面用一个整数来简单看下怎么使用

var intList = SingleLinkedList<Int>()
intList.add(11)
intList.add(22)
intList.add(33)
intList.add(44)
intList.set(1, 222)

intList.add(100, 55)
intList.add(2, 66)
intList.add(intList.size, 77)
intList.remove(0)
intList.remove(2)
intList.remove(intList.size - 1)
print(intList.indexOf(66))

上述自定义单链表实现Equatable协议,在indexOf方法中会用,用户自定义类要自己定义比较逻辑,例如下面测试代码,定义了实现Equatable协议的Person类,在类中重载==运算符。

class Person: Equatable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        lhs.age == rhs.age
    }
    
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}


var pList = SingleLinkedList<Person>()
var p1 = Person(name: "a", age: 1)
var p2 = Person(name: "b", age: 2)
var p3 = Person(name: "b", age: 1)
pList.add(p1)
pList.add(p2)
print(pList.indexOf(p3))

如果有虚拟头节点,可以在add和remove方法中将其逻辑统一。

// MARK: 在index位置添加节点对象
func add(_ index: Int, _ element: T) {
    // 最好:O(1) 最坏:O(n) 平均:O(n)
    if !rangeCheckForAdd(index) {
        return
    }
    let prev = index == 0 ? head : node(index - 1)
    prev?.next = Node(element: element, next: prev?.next)

    size += 1
}

// MARK: 删除index位置对应节点对象
@discardableResult
func remove(_ index: Int) -> T? {
    // 最好:O(1) 最坏:O(n) 平均:O(n)
    if !rangeCheck(index) {
        return nil
    }
    var current = head
    let prev = index == 0 ? head : node(index - 1)
    current = prev?.next
    prev?.next = current?.next
    size -= 1
    return current?.element
}