链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的。
首先定义一个节点:
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
}