[Swift][๋ฒ์ญ] ์ค์ํํธ์ ์๋ฃ๊ตฌ์กฐ์ ์๊ณ ๋ฆฌ์ฆ - ์น์ 2. ๊ธฐ์ด ์๋ฃ๊ตฌ์กฐ - ์ฑํฐ6-1. ์ฐ๊ฒฐ๋ฆฌ์คํธ
Raywenderlich.com ์์ ๋์จ Data Structures & Algorithms in Swift ์ฑ ์ ๋ฐ๋ชจ ๊ณต๊ฐ๋ณธ์ ๋ฒ์ญํ์์ต๋๋ค. ์ฆ๊ฒ๊ฒ ๋ด์ฃผ์ธ์.
https://www.raywenderlich.com/books/data-structures-algorithms-in-swift
์น์ 2. ๊ธฐ์ด ์๋ฃ๊ตฌ์กฐ Elementary Data Structure
์ฑํฐ 6. ์ฐ๊ฒฐ ๋ฆฌ์คํธ Linked Lists
์ฐ๊ฒฐ๋ฆฌ์คํธ๋ ๊ฐ๋ค์ด ์ ํ์ ์ด๊ณ ์ผ๋ฐฉํฅ์ ์ธ ์ํ์ค๋ก ๋ฐฐ์น๋ ์ฝ๋ ์ ์ ๋๋ค. ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ ์ค์ํํธ ๋ฐฐ์ด๊ณผ ๊ฐ์ ์ฐ์์ ์ฅ ์ต์ ์ ๋นํด ์ด๋ก ์ ์ธ ์ฐ์๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ๋ฆฌ์คํธ์ ์๋ถ๋ถ์์ ์ฝ์ ์ญ์ ๋ ์์์๊ฐ(constant time)์ด ๊ฑธ๋ฆผ
- ์ ๋ขฐํ ์ ์๋ ์ฑ๋ฅ ํน์ฑ
์ ๋ค์ด์ด๊ทธ๋จ์์ ๋ณด์ด๋ ๊ฒ์ฒ๋ผ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ ๋ ธ๋๋ค์ ์ฒด์ธ์ ๋๋ค. ๋ ธ๋์๋ ๋๊ฐ์ง ์๋ฌด๊ฐ ์์ต๋๋ค.
- ๊ฐ์ ๋ณด์
- ๋ค์ ๋ ธ๋์ ๋ ํผ๋ฐ์ค๋ฅผ ๋ณด์ . ๋ค์ ๋ ธ๋ ๋ ํผ๋ฐ์ค๊ฐ nil ์ผ ๊ฒฝ์ฐ ๋ฆฌ์คํธ์ ๋์ ์๋ฏธ
์ด๋ฒ ์ฑํฐ์์๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ๊ตฌํํ๊ณ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๊ด๋ จ๋ ์ผ๋ฐ์ ์ธ ์์ ์ ๋ํด ๋ฐฐ์ธ ๊ฒ์ ๋๋ค. ๊ฐ ์์ ์ ์๊ฐ ๋ณต์ก๋๋ฅผ ๋ฐฐ์ฐ๊ณ ์ค์ํํธ์ ๋ฉ์ง ๊ธฐ๋ฅ์ธ Copy On Write(COW, ์์์ ๊ณต์ ) ์ ๊ตฌํํ ๊ฒ์ ๋๋ค.
์ด๋ฒ ์ฑํฐ์ ์คํํฐ ํ๋ ์ด๊ทธ๋ผ์ด๋๋ฅผ ์ด์ด ์ฝ๋๋ก ๋น ์ ธ๋ด ์๋ค.
๋ ธ๋ Node
Sources ๋๋ ํ ๋ฆฌ์ Node.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
}
}
extension Node: CustomStringConvertible {
public var description: String {
guard let next = next else {
return "\(value)"
}
return "\(value) -> " + String(describing: next) + " "
}
}
ํ๋ ์ด๊ทธ๋ผ์ด๋ ํ์ด์ง๋ก ์ด๋ํ์ฌ ๋ค์์ ์ถ๊ฐํฉ๋๋ค.
example(of: "creating and linking nodes") {
let node1 = Node(value: 1)
let node2 = Node(value: 2)
let node3 = Node(value: 3)
node1.next = node2
node2.next = node3
print(node1)
}
์ฌ๋ฌ๋ถ์ ๋ฐฉ๊ธ ์ธ๊ฐ์ ๋ ธ๋๋ฅผ ๋ง๋ค๊ณ ์ด๋ค์ ์ฐ๊ฒฐํ์์ต๋๋ค.
์ฝ์ ์ฐฝ์์ ์๋ ์์ํ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of creating and linking nodes---
1 -> 2 -> 3
๋ฆฌ์คํธ๋ฅผ ๋ง๋๋ ์ด ๋ฐฉ๋ฒ์ ์ค์ฉ์ฑ์ ๊ดํด์๋ ์์ง ๋ง์ด ๋ถ์กฑํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ผ๋ก ๊ธด ๋ฆฌ์คํธ๋ฅผ ๋ง๋ ๋ค๋ฉด ์ค์ฉ์ ์ด์ง ๋ชปํ ๊ฒ์ ๋ฐ๋ก ์ ์ ์์ ๊ฒ์ ๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ์ค์ด๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ LinkedList ๋ฅผ ๋น๋ํด์ Node ์ค๋ธ์ ํธ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฅ ํ๋ฉด ๋ฉ๋๋ค.
์ฐ๊ฒฐ๋ฆฌ์คํธ LinkedList
LinkedList.swift ๋ฅผ ์์ฑํ๊ณ ์๋๋ฅผ ํ์ผ์ ์ถ๊ฐํฉ๋๋ค.
public struct LinkedList<Value> {
public var head: Node<Value>?
public var tail: Node<Value>?
public init() {}
public var isEmpty: Bool {
head == nil
}
}
extension LinkedList: CustomStringConvertible {
public var description: String {
guard let head = head else {
return "Empty list"
}
return String(describing: head)
}
}
๋งํฌ๋๋ฆฌ์คํธ๋ head ์ tail ์ด๋ผ๋ ๊ฐ๋ ์ด ์์ต๋๋ค. ๊ฐ๊ฐ ๋ฆฌ์คํธ์ ์ฒซ๋ฒ์งธ ๋ ธ๋์ ๋ง์ง๋ง ๋ ธ๋๋ฅผ ์๋ฏธํฉ๋๋ค.
๋ฆฌ์คํธ์ ๊ฐ(์์) ์ถ๊ฐํ๊ธฐ
์์ ์ธ๊ธํ ๋ฐ์ ๊ฐ์ด, Node ๊ฐ์ฒด๋ฅผ ๊ด๋ฆฌํ๋ ์ธํฐํ์ด์ค๊ฐ ์ ๊ณต๋ฉ๋๋ค. ๋จผ์ ์์๋ฅผ ์ถ๊ฐํด๋ด ์๋ค. ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๊ฐ์ ์ถ๊ฐํ๋ ๋ฐ๋ ๊ฐ๊ฐ ๋ค๋ฅธ ์ฑ๋ฅ ํน์ฑ์ ๊ฐ์ง๊ณ ์๋ 3๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
- push: ๊ฐ์ ๋ฆฌ์คํธ ์์ ์ถ๊ฐํ๊ธฐ
- append: ๊ฐ์ ๋ฆฌ์คํธ ๋์ ์ถ๊ฐํ๊ธฐใ ฃ
- insert(after:): ๊ฐ์ ํน์ ๋ ธ๋ ๋ค์์ ์ถ๊ฐํ๊ธฐ
์์ผ๋ก ์ฐ๋ฆฌ๋ ์ด ์ธ๊ฐ์ง๋ฅผ ๋ค์ ์น์ ์์ ๊ตฌํํด๋ณด๊ณ ๊ฐ๊ฐ์ ์ฑ๋ฅํน์ฑ์ ๋ถ์ํ ๊ฒ์ ๋๋ค.
ํธ์ ์์ push operations
๋ฆฌ์คํธ์ ๋งจ ์์ ๊ฐ์ ์ถ๊ฐํ๋ push ์์ ์ head-first insertion ์ด๋ผ๊ณ ๋ ํฉ๋๋ค. ์ฝ๋๋ ๊ต์ฅํ ๋จ์ํฉ๋๋ค.
์๋ ๋ฉ์๋๋ฅผ LinkedList์ ์ถ๊ฐํ์ธ์.
public mutating func push(_ value: Value) {
head = Node(value: value, next: head)
if tail == nil {
tail = head
}
}
๋น ๋ฆฌ์คํธ์ ๊ฐ์ ํธ์ํ๋ฉด, ์๋ก์ด ๋ ธ๋๋ ๋ฆฌ์คํธ์ head ์ด์ tail ์ด ๋ฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋์์ ์๋๋ฅผ ์ถ๊ฐํ์ธ์.
example(of: "push") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print(list)
}
์ฝ์์ฐฝ์์ ์๋์ ๊ฐ์ด ์ถ๋ ฅ๋ฉ๋๋ค.
---Example of push---
1 -> 2 -> 3
push ์ pop ์ ๋ ๋ค ์๊ฐ๋ณต์ก๋๊ฐ O(1) ์ ๋๋ค.
append ์์
๋ค์์ผ๋ก ์ดํด๋ณผ ์์ ์ append ์ ๋๋ค. ๋ฆฌ์คํธ์ ๊ฐ์ฅ ๋์ ๊ฐ์ ์ถ๊ฐํ๋ฉฐ, tail-end insertion ์ด๋ผ๊ณ ํฉ๋๋ค.
LinkedList.swift ์์ ์๋ ์ฝ๋๋ฅผ push ์๋์ ์ ๋ ฅํ์ธ์.
public mutating func append(_ value: Value) {
// 1
guard !isEmpty else {
push(value)
return
}
// 2
tail!.next = Node(value: value)
// 3
tail = tail!.next
}
์ด ์ฝ๋๋ค์ ๋น๊ต์ ๊ฐ๋จํฉ๋๋ค.
- ์ด์ ์ ์๊ธฐํ ๊ฒ์ฒ๋ผ ๋ฆฌ์คํธ๊ฐ ๋น์ด์๋ค๋ฉด head ์ tail ์ ์ ๋ ธ๋๋ก ์ ๋ฐ์ดํธ ํด์ฃผ์ด์ผํฉ๋๋ค. ๋น ๋ฆฌ์คํธ์ append ๋ ๊ธฐ๋ฅ์ ์ผ๋ก push ์ ๋์ผํ๋ฏ๋ก push ๋ฅผ ํธ์ถํ์ฌ ์์ ์ ์ํํฉ๋๋ค.
- ๊ทธ ์ธ ๋ชจ๋ ๊ฒฝ์ฐ ์ฌ๋ฌ๋ถ์ tail ๋ค์ ์ ๋ ธ๋๋ฅผ ๋ง๋ค๊ฒ ๋ฉ๋๋ค. guard ๋ฌธ์ ์ด์ฉํ์ฌ isEmpty ์ผ์ด์ค๋ฅผ ํธ์ํ๋ฏ๋ก ๋ช ์์ ์ธ๋ํ์ Force unwrapping ์ ์ ์ํ๋ฉ๋๋ค.
- tail-end insertion ์ด๋ฏ๋ก ์ฌ๋ฌ๋ถ์ ์ ๋ ธ๋๋ ๋ฆฌ์คํธ์ tail์ด ๋ฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋๋ก ๋์๊ฐ์ ๋ค์ ์ฝ๋๋ฅผ ์๋์ ์์ฑํฉ๋๋ค.
example(of: "append") {
var list = LinkedList<Int>()
list.append(1)
list.append(2)
list.append(3)
print(list)
}
์๋ ๊ฒฐ๊ณผ๊ฐ ์ฝ์์ฐฝ์์ ์ถ๋ ฅ๋ฉ๋๋ค.
---Example of append---
1 -> 2 -> 3
insert(after:) ์์
๋ฆฌ์คํธ์ ๊ฐ์ ์ถ๊ฐํ๋ ์ธ๋ฒ์งธ์ด์ ๋ง์ง๋ง ์์ ์ insert(after:) ์ ๋๋ค. ์ด ์์ ์ ๋ฆฌ์คํธ์ ํน์ ์์น์ ๊ฐ์ ์ฝ์ ํ๋ ์์ ์ผ๋ก ๋๊ฐ์ง ๋จ๊ณ๊ฐ ํ์ํฉ๋๋ค.
- ๋ฆฌ์คํธ์ ํน์ ๋ ธ๋๋ฅผ ์ฐพ๋๋ค.
- ์๋ก์ด ๋ ธ๋๋ฅผ ์ฝ์ ํ๋ค.
๋จผ์ ๊ฐ์ ์ฝ์ ํ๊ณ ์ ํ๋ ๋ ธ๋๋ฅผ ์ฐพ๋ ์ฝ๋๋ฅผ ๊ตฌํํฉ๋๋ค. LinkedList.swift, ์์ append ์๋์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
public func node(at index: Int) -> Node<Value>? {
// 1
var currentNode = head
var currentIndex = 0
// 2
while currentNode != nil && currentIndex < index {
currentNode = currentNode!.next
currentIndex += 1
}
return currentNode
}
node(at:) ์ ์ฃผ์ด์ง ์ธ๋ฑ์ค์ ๋ฐ๋ผ ๋ฆฌ์คํธ ์์ ๋ ธ๋๋ฅผ ๊ฒ์ํฉ๋๋ค. ๋ฆฌ์คํธ์ ๋ ธ๋๋ head ๋ ธ๋์์๋ถํฐ๋ฐ์ ์ ๊ทผํ ์ ์์ผ๋ฏ๋ก ๋ฐ๋ณต์ ์ธ ์ํ๋ฅผ ํด์ผํฉ๋๋ค. ํ๋์ฉ ๋ฐ๋ผ๊ฐ๋ด ์๋ค.
- head ์ ์๋ก์ด ๋ ํผ๋ฐ์ค๋ฅผ ์์ฑํ๊ณ ํ์ฌ ์ํํ๊ณ ์๋ ์์น๋ฅผ ์ถ์ ํฉ๋๋ค.
- while ๋ฐ๋ณต๋ฌธ์ ์ด์ฉํ์ฌ ์ํ๋ ์ธ๋ฑ์ค๊น์ง ๋ฆฌ์คํธ์ ์๋ซ์ชฝ์ผ๋ก ๋ ํผ๋ฐ์ค๋ฅผ ์ด๋ํฉ๋๋ค. ๋น ๋ฆฌ์คํธ์ด๊ฑฐ๋ ๋ฆฌ์คํธ์ ๋ฒ์๋ฅผ ์ด๊ณผํ๋ ์ธ๋ฑ์ค๋ nil ์ ๋ฐํํฉ๋๋ค.
์ด์ ์๋ก์ด ๋ ธ๋๋ฅผ ์ฝ์ ํด์ผ ํฉ๋๋ค. ์๋ ๋ฉ์๋๋ฅผ node(at:) ์๋์ ์ถ๊ฐํฉ๋๋ค.
// 1
@discardableResult
public mutating func insert(_ value: Value,
after node: Node<Value>)
-> Node<Value> {
// 2
guard tail !== node else {
append(value)
return tail!
}
// 3
node.next = Node(value: value, next: node.next)
return node.next!
}
์ฌ๋ฌ๋ถ์ด ํ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- @discardableResult ๋ ์ปดํ์ผ๋ฌ๊ฐ ๊ฒฝ๊ณ ํ์ง ์๊ณ ๋ ํธ์ถ์๊ฐ ๋ฉ์๋์ ๋ฐํ๊ฐ์ ๋ฌด์ํ ์ ์์ต๋๋ค.
- ์ด ๋ฉ์๋๊ฐ tail ๋ฉ์๋์ ํจ๊ป ํธ์ถ๋๋ ๊ฒฝ์ฐ ๊ธฐ๋ฅ์ ์ผ๋ก ๋๋ฑํ append ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฒ ๋ฉ๋๋ค. ์ด๋ tail ๋ ธ๋๋ฅผ ์ ๋ฐ์ดํธํฉ๋๋ค.
- ๊ทธ ์ธ์๋ ์ ๋ ธ๋๋ฅผ ๋ฆฌ์คํธ์ ๋๋จธ์ง์ ์ฐ๊ฒฐํ๊ณ ์ ๋ ธ๋๋ฅผ ๋ฐํํฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋ ํ์ด์ง๋ก ๋์๊ฐ ํ ์คํธํฉ๋๋ค. ์๋ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์ถ๊ฐํฉ๋๋ค.
example(of: "inserting at a particular index") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Before inserting: \(list)")
var middleNode = list.node(at: 1)!
for _ in 1...4 {
middleNode = list.insert(-1, after: middleNode)
}
print("After inserting: \(list)")
}
์๋ ๊ฒฐ๊ณผ๋ฌผ์ ํ์ธํ ์ ์์ต๋๋ค.
---Example of inserting at a particular index---
Before inserting: 1 -> 2 -> 3
After inserting: 1 -> 2 -> -1 -> -1 -> -1 -> -1 -> 3
์ฑ๋ฅํ๊ฐ
ํด! ์ด์ ๊น์ง ์ ํด์์ต๋๋ค. ์์ฝํ๋ฉด ์ฐ๋ฆฌ๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๊ฐ์ ์ถ๊ฐํ๋ ์ธ๊ฐ์ง ์์ ๊ณผ ํน์ ์ธ๋ฑ์ค์ ์์นํ ๋ ธ๋๋ฅผ ์ฐพ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ์์ต๋๋ค.
push | append | insert(after:) | node(at:) | |
๋์ Behaviour | head์ ์ฝ์ | tail์ ์ฝ์ | ํน์ ๋ ธ๋ ๋ค์์ ์ฝ์ | ์ฃผ์ด์ง ์ธ๋ฑ์ค์ ๋ ธ๋๋ฅผ ๋ฐํ |
์๊ฐ๋ณต์ก๋ Time complexity | O(1) | O(1) | O(1) | O(i), i ๋ ์ฃผ์ด์ง ์ธ๋ฑ์ค |
๋ค์์ผ๋ก ์ด์ ๋ฐ๋๋๋ ์ญ์ ์์ ์ ์ดํด๋ด ์๋ค.
๋ฆฌ์คํธ์์ ๊ฐ(์์) ์ญ์ ํ๊ธฐ
๋ ธ๋ ์ญ์ ์๋ ์ธ๊ฐ์ง ๋ฐฉ์์ ์ฃผ์ ์์ ์ด ์์ต๋๋ค.
- pop: ๋ฆฌ์คํธ ๋งจ ์์ ๊ฐ์ ์ญ์
- removeLast: ๋ฆฌ์คํธ ๋งจ ๋ง์ง๋ง ๊ฐ์ ์ญ์
- remove(at:): ๋ฆฌ์คํธ ํน์ ์์น์ ๊ฐ์ ์ญ์
์ ์ธ๊ฐ์ง๋ฅผ ๊ตฌํํ๊ณ ์ฑ๋ฅ ํน์ฑ์ ํ๊ฐํด๋ด ์๋ค.
pop ์์
๋ฆฌ์คํธ์ ์์ ์๋ ๊ฐ์ ์ญ์ ํ๋ ๊ฒ์ pop ์ ๋๋ค. ์ด ์์ ์ push ๋งํผ ๊ฐ๋จํฉ๋๋ค.๋ฐ๋ก ์์ํฉ์๋ค.
์๋ ๋ฉ์๋๋ฅผ LinkedList ์ ์ถ๊ฐํฉ๋๋ค.
@discardableResult
public mutating func pop() -> Value? {
defer {
head = head?.next
if isEmpty {
tail = nil
}
}
return head?.value
}
pop ์ ๋ฆฌ์คํธ์์ ์ญ์ ๋๋ ๊ฐ์ ๋ฐํฅํํฉ๋๋ค. ๋ฆฌ์คํธ๊ฐ ๋น์ด์์ ์๋ ์์ผ๋ฏ๋ก ์ด ๊ฐ์ ์ต์ ๋์ ๋๋ค.
head ๋ ธ๋๋ฅผ ์๋๋ก ์ด๋ํ์ฌ ๋ฆฌ์คํธ์ ์ฒซ๋ฒ์งธ ๋ ธ๋๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ๊ฑฐํ์์ต๋๋ค. ARC๋ ์ด๋ ๋ ํผ๋ฐ์ค๋ ๋ถ์ด ์์ง ์์ผ๋ฏ๋ก ๋ฉ์๋๊ฐ ์ข ๋ฃ๋๋ฉด ๋ฉ๋ชจ๋ฆฌ์์ ์ค๋๋ ๋ ธ๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ๋ง์ฝ ๋ฆฌ์คํธ๊ฐ ๋น๊ฒ ๋๋ฉด tail ์ nil ๋ก ์ค์ ํฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋ ํ์ด์ง๋ก ๋์๊ฐ์ ์๋ ์ฝ๋๋ฅผ ๋ฐ์ ์ถ๊ฐํ์ฌ ํ ์คํธํฉ๋๋ค.
example(of: "pop") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Before popping list: \(list)")
let poppedValue = list.pop()
print("After popping list: \(list)")
print("Popped value: " + String(describing: poppedValue))
}
์๋ ๊ฒฐ๊ณผ๋ฅผ ์ฝ์์ฐฝ์์ ๋ณผ ์ ์์ต๋๋ค.
---Example of pop---
Before popping list: 1 -> 2 -> 3
After popping list: 2 -> 3
Popped value: Optional(1)
removeLast ์์
๋ฆฌ์คํธ์ ๋ง์ง๋ง ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ์ ์ฝ๊ฐ ๋ถํธํฉ๋๋ค. tail ๋ ธ๋์ ๋ํ ์ฐธ์กฐ๊ฐ ์์ด๋ ๊ทธ ์์ ์๋ ๋ ธ๋์ ๋ํ ์ฐธ์กฐ๊ฐ ์์ผ๋ฉด ์๋ผ๋ผ ์ ์์ต๋๋ค. ๋๋ฌธ์ ์ฌ๋ฌ๋ถ์ ์๊ณ ์ค๋ฌ์ด ํ์์ ํด์ผํฉ๋๋ค. ์๋ ์ฝ๋๋ฅผ pop ๋ฐ์ ์ถ๊ฐํฉ๋๋ค.
@discardableResult
public mutating func removeLast() -> Value? {
// 1
guard let head = head else {
return nil
}
// 2
guard head.next != nil else {
return pop()
}
// 3
var prev = head
var current = head
while let next = current.next {
prev = current
current = next
}
// 4
prev.next = nil
tail = prev
return current.value
}
์ฝ๋์์ ์ผ์ด๋๋ ์ผ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋ง์ฝ head ๊ฐ nil์ผ ๊ฒฝ์ฐ ์๋ฌด๊ฒ๋ ์ ๊ฑฐ๋์ง ์์ต๋๋ค. nil ์ ๋ฐํํฉ๋๋ค.
- ๋ง์ฝ ๋ฆฌ์คํธ๊ฐ ํ ๊ฐ์ ๋ ธ๋๋ก๋ง ๊ตฌ์ฑ๋์ด ์๋ค๋ฉด removeLast ๋ ๊ธฐ๋ฅ์ ์ผ๋ก pop ๊ณผ ๋์ผํฉ๋๋ค. pop ์ head ์ tail ์ ๋ ํผ๋ฐ์ค ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๋ฏ๋ก, ์์ ์ ์์ํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
- current.next ๊ฐ nil ์ผ ๋๊น์ง ๊ณ์ ๋ค์ ๋ ธ๋๋ฅผ ๊ฒ์ํฉ๋๋ค. ์ฆ current ๊ฐ ๋ฆฌ์คํธ์ ๋ง์ง๋ง ๋ ธ๋๋ฅผ ์๋ฏธํ๋ ์์ ์ ๋๋ค.
- current ๊ฐ ๋ง์ง๋ง ๋ ธ๋์ด๋ฉด, prev.next ์ ๋ ํผ๋ฐ์ค๋ฅผ ์ด์ฉํ์ฌ ๋์ด๋ด๋ฉด ๋ฉ๋๋ค. tail ๋ ํผ๋ฐ์ค๋ฅผ ๊ผญ ์ ๋ฐ์ดํธ ํด์ผํฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋ ํ์ด์ง๋ก ๋์๊ฐ์ ๋ค์ ์ฝ๋๋ฅผ ์๋์ ์ถ๊ฐํฉ๋๋ค.
example(of: "removing the last node") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Before removing last node: \(list)")
let removedValue = list.removeLast()
print("After removing last node: \(list)")
print("Removed value: " + String(describing: removedValue))
}
์๋ ์ฝ์ ์ฐฝ์์ ์ด๋ฌํ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of removing the last node---
Before removing last node: 1 -> 2 -> 3
After removing last node: 1 -> 2
Removed value: Optional(3)
removeLast ๋ ๋ฆฌ์คํธ์ ๋๊น์ง ์ํํด์ผ ํฉ๋๋ค. ์ด๋ O(n) ์์
์ผ๋ก ์๋์ ์ผ๋ก ๋น์ฉ์ด ๋ง์ด ๋๋ ์์
์
๋๋ค.
remove(after:) ์์
๋ง์ง๋ง ์ ๊ฑฐ ์์ ์ ๋ฆฌ์คํธ์ ํน์ ์์น์ ์๋ ํน์ ๋ ธ๋๋ฅผ ์ญ์ ํ๋ ๊ฒ์ ๋๋ค. insert(after:) ์ ๋งค์ฐ ์ ์ฌํฉ๋๋ค. ๋จผ์ ์ฌ๋ฌ๋ถ์ ์ ๊ฑฐํ๊ณ ์ ํ๋ ๋ ธ๋์ ๋ฐ๋ก ์ ๋ ธ๋๋ฅผ ์ฐพ๊ณ , ๋ค์์ผ๋ก๋ ์ฐ๊ฒฐ์ ๋์ ๊ฒ์ ๋๋ค.
LinkedList.swift ๋ก ๋์๊ฐ์ removeLast ์๋์ ๋ค์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
@discardableResult
public mutating func remove(after node: Node<Value>) -> Value? {
defer {
if node.next === tail {
tail = node
}
node.next = node.next?.next
}
return node.next?.value
}
๋ ธ๋์ ์ฐ๊ฒฐ์ ํด์ ํ๋ฉด defer ๋ธ๋ก์ด ์คํ๋ฉ๋๋ค. ๋ง์ฝ ์ญ์ ๋ ๋ ธ๋๊ฐ tail ๋ ธ๋์ผ ๊ฒฝ์ฐ, tail ๋ ํผ๋ฐ์ค๊ฐ ๋ฐ๋์ ์ ๋ฐ์ดํธ ๋์ด์ผํ๋ฏ๋ก ํน๋ณํ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
ํ๋ ์ด๊ทธ๋ผ์ด๋๋ก ๋์๊ฐ์๋ค. ์ฌ๋ฌ๋ถ์ ๋ฐฉ๋ฒ์ ์๊ณ ์์ด์.
example(of: "removing a node after a particular node") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Before removing at particular index: \(list)")
let index = 1
let node = list.node(at: index - 1)!
let removedValue = list.remove(after: node)
print("After removing at index \(index): \(list)")
print("Removed value: " + String(describing: removedValue))
}
์ฝ์ ์ฐฝ์์ ์๋ ์ถ๋ ฅ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of removing a node after a particular node---
Before removing at particular index: 1 -> 2 -> 3
After removing at index 1: 1 -> 3
Removed value: Optional(2)
๋ ๋ง์ ์์๋ฅผ ์ถ๊ฐํ๊ณ ์ธ๋ฑ์ค ๊ฐ์ ๊ฐ์ง๊ณ ๋์๋ณด์ธ์. insert(at:) ๊ณผ ์ ์ฌํ๊ฒ ์ด ์์ ์ ์๊ฐ ๋ณต์ก๋๋ O(1) ์ ๋๋ค. ํ์ง๋ง ๊ทธ์ ์ ํน์ ๋ ธ๋์ ๋ ํผ๋ฐ์ค๊ฐ ์์ด์ผ ํฉ๋๋ค.
์ฑ๋ฅ ํ๊ฐ
์ด์ ๋๋ค๋ฅธ ์ฒดํฌํฌ์ธํธ์ ๋์ฐฉํ๋ค์! ์์ฝํ์๋ฉด ์ฌ๋ฌ๋ถ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ์์ ๊ฐ์ ์ญ์ ํ๋ ์ธ๊ฐ์ง ์์ ์ ๊ตฌํํ์์ต๋๋ค.
pop | removeLast | remove(after:) | |
๋์ Behaviour | head๋ฅผ ์ญ์ | tail์ ์ญ์ | ๋ฐ๋ก ๋ค์ ๋ ธ๋๋ฅผ ์ญ์ |
์๊ฐ๋ณต์ก๋ Time complexity | O(1) | O(n) | O(1) |
์ด ์์ ์์ ์ฌ๋ฌ๋ถ์ ๋๋ถ๋ถ ํ๋ก๊ทธ๋๋จธ๊ฐ ์ฐ๊ด ์์ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ์์ต๋๋ค. ํ์ง๋ง ์ค์ํํธ ์๋งจํฑ์ ๊พธ๋ฏธ๊ธฐ(adorn)์ํด์๋ ํด์ผ๋ ์ผ์ด ์์ต๋๋ค. ์ด๋ฒ ์ฑํฐ์ ๋๋จธ์ง ์ ๋ฐ์์๋ ์ธํฐํ์ด์ค๋ฅผ ๊ฐ๋ฅํ ๋น ๋ฅด๊ฒ(Swifty) ๋ง๋๋ ๊ฒ์ ์ด์ ์ ๋ง์ถ๊ฒ ์ต๋๋ค.
๐ ๋ฒ์ญ ์๋ฆฌ์ฆ ๋งํฌ
0๏ธโฃ ์น์ 0. ์์ํ๊ธฐ์ ์
1๏ธโฃ ์น์ 1. ์๊ฐ Introduction
> ์ฑํฐ 1.์ ์๋ฃ๊ตฌ์กฐ์ ์๊ณ ๋ฆฌ์ฆ์ ๋ฐฐ์์ผํ ๊น์? / ์ฑํฐ 2. ๋ณต์ก๋ Complexity
> ์ฑํฐ3. ์ค์ํํธ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ Swift Standard Library
1๏ธโฃ ์น์ 2. ๊ธฐ์ด ์๋ฃ๊ตฌ์กฐ Elementary Data Structure
> ์ฑํฐ 4. ์คํ Stacks / ์ฑํฐ 5. ์คํ ๋์ ๊ณผ์ Stack Challenges
> ์ฑํฐ 6-1. ์ฐ๊ฒฐ๋ฆฌ์คํธ Linked List (์ฐ๊ฒฐ๋ฆฌ์คํธ ์ ์, ์์ ์ถ๊ฐ, ์ญ์ )
> ์ฑํฐ 6-2. ์ฐ๊ฒฐ๋ฆฌ์คํธ Linked List (์ค์ํํธ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฝ๋ ์ ํ๋กํ ์ฝ, ์นด์ฐ Copy-On-Write, ๋ฐธ๋ฅ ์๋งจํฑ)
> ์ฑํฐ 7. ์ฐ๊ฒฐ๋ฆฌ์คํธ ๋์ ๊ณผ์ Linked List Challenges
๋ง์น๋ฉฐ
์ค๋๋ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ๋๊ธ๋ก, ๋์์ด ๋์ จ๋ค๋ฉด ๊ณต๊ฐ ๋ถํ๋๋ฆฝ๋๋ค.
ํน์ ์์ ํ๊ฑฐ๋ ํผ๋๋ฐฑํ์ค ๋ด์ฉ ์๋ค๋ฉด ์ธ์ ๋ ๋๊ธ๋ก ๋ถํ๋๋ฆฝ๋๋ค.
๊ฐ์ฌํฉ๋๋ค.
๋๊ธ