[Swift][๋ฒ์ญ] ์ค์ํํธ์ ์๋ฃ๊ตฌ์กฐ์ ์๊ณ ๋ฆฌ์ฆ - ์น์ 2. ๊ธฐ์ด ์๋ฃ๊ตฌ์กฐ - ์ฑํฐ7. ์ฐ๊ฒฐ๋ฆฌ์คํธ ๋์ ๊ณผ์
Raywenderlich.com ์์ ๋์จ Data Structures & Algorithms in Swift ์ฑ ์ ๋ฐ๋ชจ ๊ณต๊ฐ๋ณธ์ ๋ฒ์ญํ์์ต๋๋ค. ์ฆ๊ฒ๊ฒ ๋ด์ฃผ์ธ์.
https://www.raywenderlich.com/books/data-structures-algorithms-in-swift
์น์ 2. ๊ธฐ์ด ์๋ฃ๊ตฌ์กฐ Elementary Data Structure
์ฑํฐ 7. ์ฐ๊ฒฐ ๋ฆฌ์คํธ ๋์ ๊ณผ์ Linked Lists Challenges
์ด๋ฒ ์ฑํฐ์์ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ก ์์ฃผ ์ฌ์ฉ๋๋ ๋ค์ฏ๊ฐ์ง ๋ฌธ์ ๋ค์ ๋ค๋ค๋ณผ ๊ฒ๋๋ค. ์ด ๋ฌธ์ ๋ค์ ๋ค๋ฅธ ๋์ ๊ณผ์ ์ ๋นํด์๋ ์๋์ ์ผ๋ก ์ฝ๊ณ , ์๋ฃ ๊ตฌ์กฐ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์ง์์ ๊ณต๊ณ ํ๊ฒ ํด์ค ๊ฒ์ ๋๋ค.
Start project๋ฅผ ์ด๋ฉด ์๋ ๋์ ๊ณผ์ ๋ค์ ๋ณผ ์ ์์ต๋๋ค.
๋์ ๊ณผ์ 1: ๊ฑฐ๊พธ๋ก ์ถ๋ ฅํ๊ธฐ
์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๋ ธ๋๋ฅผ ๊ฑฐ๊พธ๋ก ์ถ๋ ฅํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค.
// ์์
1 -> 2 -> 3 -> nil
// ์๋์ ๊ฐ์ ํํ๋ก ์ถ๋ ฅ์ด ๋์ด์ผ ํฉ๋๋ค.
3
2
1
๋์ ๊ณผ์ 2: ๊ฐ์ด๋ฐ ๋ ธ๋ ์ฐพ๊ธฐ
์ฐ๊ฒฐ๋ฆฌ์คํธ์์ ์ค์์ ์์นํ ๋ ธ๋๋ฅผ ์ฐพ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค.
// ์์
1 -> 2 -> 3 -> 4 -> nil
// ์ฌ๊ธฐ์ ๊ฐ์ด๋ฐ ๋
ธ๋๋ 3์
๋๋ค.
1 -> 2 -> 3 -> nil
// ์ฌ๊ธฐ์ ๊ฐ์ด๋ฐ ๋
ธ๋๋ 2์
๋๋ค.
๋์ ๊ณผ์ 3: ์ฐ๊ฒฐ๋ฆฌ์คํธ ๋ค์ง๊ธฐ
์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์์๋ฅผ ๋ค์ง๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค. ๋ ธ๋๋ฅผ ์ง์ ๋ค๋ฃจ์ด์ ๋ฐ๋๋ฐฉํฅ์ผ๋ก ์ฐ๊ฒฐ๋๊ฒ ํฉ๋๋ค.
// ์์
// ์
1 -> 2 -> 3 -> nil
// ํ
3 -> 2 -> 1 -> nil
๋์ ๊ณผ์ 4: ์ฐ๊ฒฐ๋ฆฌ์คํธ 2๊ฐ ํฉ์น๊ธฐ
๋๊ฐ์ ์ ๋ ฌ๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ํฉ์ณ์ ํ๋์ ์ ๋ ฌ๋ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ก ๋ง๋๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค. ๋ชฉํ๋ ๋๊ฐ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์๋ ์์๋ฅผ ์ ๋ ฌ๋ ์์๋ก ๊ฐ์ง๊ณ ์๋ ์๋ก์ด ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋๋ค. ์ ๋ ฌ์์๋ ์ค๋ฆ์ฐจ์์ผ๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค.
// ์์
// ์ฐ๊ฒฐ๋ฆฌ์คํธ 1
1 -> 4 -> 10 -> 11
// ์ฐ๊ฒฐ๋ฆฌ์คํธ 2
-1 -> 2 -> 3 -> 6
// ํฉ์ณ์ง ์ฐ๊ฒฐ๋ฆฌ์คํธ
-1 -> 1 -> 2 -> 3 -> 4 -> 6 -> 10 -> 11
๋์ ๊ณผ์ 5: ํน์ ์์์ ์ผ์นํ๋ ๋ชจ๋ ๋์์ ์ ๊ฑฐ
์ฐ๊ฒฐ๋ฆฌ์คํธ์ ํน์ ์์์ ์ผ์นํ๋ ๋ชจ๋ ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๋ ํจ์๋ฅผ ๋ง๋ค์ด๋ด ๋๋ค. ์ด์ ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๊ตฌํํด๋ณธ remove(at:) ๋ฉ์๋์ ์ ์ฌํฉ๋๋ค.
// ์์
// ์๋ณธ ๋ฆฌ์คํธ
1 -> 3 -> 3 -> 3 -> 4
// ๋ชจ๋ 3์ ์ ๊ฑฐํ ๋ฆฌ์คํธ
1 -> 4
ํด๊ฒฐ์ฑ
๋์ ๊ณผ์ 1 ํด๊ฒฐ์ฑ
๋ณด๋ค ๊ฐ๋จํ๊ฒ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ๊ท๋ฅผ ์ด์ฉํ๋ ๊ฒ์ ๋๋ค. ์ฌ๊ท๋ฅผ ์ด์ฉํ๋ฉด ์ฝ ์คํ(Call Stack)์ ๋น๋ํ ์ ์์ผ๋ฏ๋ก ์ฝ ์คํ์ด ํด์ ๋ ๋ ์ถ๋ ฅ๋ฌธ์ ํธ์ถํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
์ฒซ๋ฒ์งธ ๊ณผ์ ์ ๋ ธ๋์ ๋๊น์ง ์ฌ๊ท์ ์ผ๋ก ์ํํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ๋์์ฃผ๋ ๋ค์ ํจ์๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋์ ์ถ๊ฐํฉ๋๋ค.
private func printInReverse<T>(_ node: Node<T>?) {
// 1
guard let node = node else { return }
// 2
printInReverse(node.next)
}
- ๋จผ์ ์ฌ๊ท๋ฅผ ์ข ๋ฃํ๋ ์กฐ๊ฑด์ธ ๊ธฐ๋ณธ ์ผ์ด์ค๋ถํฐ ์์ํฉ๋๋ค. ๋ง์ฝ node ๊ฐ nil์ด๋ฉด ๋ฆฌ์คํธ ๋ง์ง๋ง์ ๋๋ฌํ๋ค๋ ๋ป์ด๋ฏ๋ก ์ข ๋ฃ์กฐ๊ฑด์ด ๋ฉ๋๋ค.
- ์ฌ๊ทํธ์ถ์ด๋ฏ๋ก ๋ค์ ๋ ธ๋๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋์ผํ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
์ถ๋ ฅ
print ๋ฌธ์ ์ถ๊ฐํ๋ ์์น์ ๋ฐ๋ผ ์ญ์์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ์ถ๋ ฅํ ์ง ์ฌ๋ถ๊ฐ ๊ฒฐ์ ๋ฉ๋๋ค.
ํจ์๋ฅผ ์๋์ ๊ฐ์ด ์ ๋ฐ์ดํธ ํฉ๋๋ค.
private func printInReverse<T>(_ node: Node<T>?) {
guard let node = node else { return }
printInReverse(node.next)
print(node.value)
}
์ฌ๊ทํธ์ถ ๋ค์์ผ๋ก ์ค๋ ์ฝ๋๋ ๊ธฐ๋ณธ ์ผ์ด์ค๊ฐ ๋ฐ๋(์ฌ๊ธฐ์๋ ์ฌ๊ทํธ์ถ์ด ๋ฆฌ์คํธ์ ๋ง์ง๋ง๊น์ง ๊ฐ์ ๋)๋์์ ๋ ํธ์ถ๋ฉ๋๋ค. ์ฌ๊ท ๋ฌธ์ด ํ๋ฆฌ๊ฒ ๋๋ฉด์ ๋ ธ๋ ๋ฐ์ดํฐ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก ์๋์ printInReverse ์์ ์ด ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
func printInReverse<T>(_ list: LinkedList<T>) {
printInReverse(list.head)
}
์๋ํด๋ณด๊ธฐ
๋ค์ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์์ฑํด๋ด ์๋ค.
example(of: "printing in reverse") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Original list: \(list)")
print("Printing in reverse:")
printInReverse(list)
}
์๋ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of printing in reverse---
Original list: 1 -> 2 -> 3
Printing in reverse:
3
2
1
๋ฆฌ์คํธ์ ๋ชจ๋ ๋ ธ๋๋ฅผ ์ํํด์ผํ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๋ O(n) ์ ๋๋ค. ๋ฌต์์ ์ผ๋ก ํจ์ ํธ์ถ ์คํ์ ์ฌ์ฉํ์ฌ ๊ฐ ์์๋ฅผ ์ฒ๋ฆฌํ๋ฏ๋ก ๊ณต๊ฐ๋ณต์ก๋ ์ญ์ O(n) ์ ๋๋ค.
๋์ ๊ณผ์ 2 ํด๊ฒฐ์ฑ
์ด ํด๊ฒฐ์ฑ ์ ๋ ๊ฐ์ ํฌ์ธํฐ๊ฐ ๋ฆฌ์คํธ์ ๋ ธ๋๋ฅผ ๋ชจ๋ ์ํํ๋ ๊ฒ์ ๋๋ค. ๋ ์ค ํ ํฌ์ธํฐ๋ ๋ค๋ฅธ ํฌ์ธํฐ๋ณด๋ค 2๋ฐฐ ๋น ๋ฅด๊ฒ ์ํํฉ๋๋ค. ๋น ๋ฅธ ํฌ์ธํฐ๊ฐ ๋ฆฌ์คํธ ๋๊น์ง ๊ฐ๊ฒ ๋๋ฉด ๋๋ฆฐ ํฌ์ธํฐ๋ ๋ฆฌ์คํธ์ ์ค์์ ์์ ๊ฒ์ ๋๋ค. ํจ์๋ฅผ ์๋์ ๊ฐ์ด ์ ๋ฐ์ดํธํ์ธ์.
func getMiddle<T>(_ list: LinkedList<T>) -> Node<T>? {
var slow = list.head
var fast = list.head
while let nextFast = fast?.next {
fast = nextFast.next
slow = slow?.next
}
return slow
}
while ์ ์ ์ธํ ๋ ๋ค์ ๋ ธ๋๋ฅผ nextFast์ ๋ฐ์ธ๋ฉํฉ๋๋ค. ๋ง์ฝ ๋ค์ ๋ ธ๋๊ฐ ์์ผ๋ฉด fast ํฌ์ธํฐ๋ฅผ nextFast ์ ๋ค์ ๋ ธ๋๋ก ์ ๋ฐ์ดํธํ์ฌ ํจ๊ณผ์ ์ผ๋ก ๋ฆฌ์คํธ๋ฅผ ๋๋ฒ ์ํํ๊ฒ ํฉ๋๋ค. slow ์ฐธ์กฐ๋ ํ๋ฒ๋ง ์ ๋ฐ์ดํธ ํฉ๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ ๋ฌ๋ ๊ธฐ๋ฒ runner’s technique ์ด๋ผ๊ณ ํฉ๋๋ค.
์๋ํด๋ณด๊ธฐ
๋ค์ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์์ฑํด๋ด ์๋ค.
example(of: "getting the middle node") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print(list)
if let middleNode = getMiddle(list) {
print(middleNode)
}
}
์๋ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of getting the middle node---
1 -> 2 -> 3
2 -> 3
ํ ๋ฒ์ ํจ์ค๋ก ๋ฆฌ์คํธ๋ฅผ ์ํํ์์ผ๋ฏ๋ก ์ด ์๊ณ ๋ฆฌ์ฆ์ ์๊ฐ ๋ณต์ก๋๋ O(n) ์ ๋๋ค. ๋ฌ๋ ๊ธฐ๋ฒ runner’s technique ์ ์ฐ๊ฒฐ๋ฆฌ์คํธ์ ์ฐ๊ด๋์ด ์๋ ๋ค์ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๋์ ๊ณผ์ 3 ํด๊ฒฐ์ฑ
์ฐ๊ฒฐ๋ฆฌ์คํธ๋ฅผ ๋ค์ง๊ธฐ ์ํด์ ๋ชจ๋ ๋ ธ๋์ ๋ฐฉ๋ฌธํ์ฌ next ์ฐธ์กฐ๋ฅผ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ์ ๋ฐ์ดํธํด์ผํฉ๋๋ค. ์ฌ๋ฌ ๋ ธ๋์ ์ฐธ์กฐ๋ค์ ๊ด๋ฆฌํด์ผํ๋ฏ๋ก ๊น๋ค๋ก์ด ์์ ์ด ๋ ์ ์์ต๋๋ค.
์ฌ์ด ๋ฐฉ๋ฒ
์ ๋น ๋ฆฌ์คํธ๋ก push ๋ฉ์๋๋ฅผ ์ด์ฉํด ๊ฐ๋จํ๊ฒ ๋ฆฌ์คํธ๋ฅผ ๋ค์ง์ ์ ์์ต๋๋ค. ์๋ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋์ ์ ๋ฐ์ดํธํ์ธ์.
extension LinkedList {
mutating func reverse() {
// 1
let tmpList = LinkedList<Value>()
for value in self {
tmpList.push(value)
}
// 2
head = tmpList.head
}
}
- ๋จผ์ ํ์ฌ ๊ฐ์ ๋ชจ๋ ์ tmpList ๋ฆฌ์คํธ์ ํธ์ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ญ์์ ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค๊ฒ ๋ฉ๋๋ค.
- head ์ฐธ์กฐ๋ฅผ ์๋ก ๋ง๋ค์ด์ง ๋ฆฌ์คํธ๋ก ๋ฐ๊ฟ์ค๋๋ค.
O(n)์ ์๊ฐ ๋ณต์ก๋์ธ๋ฐ๋ค ์ฝ๊ณ ๊ฐํธํ์ง์.
ํ์ง๋ง ์ ๊น...
๋ฆฌ์คํธ๋ฅผ ๋ค์ง๋ ๋ฐ์ O(n) ์ ์ต์ ์ ์๊ฐ๋ณต์ก๋์ง๋ง, ์ด์ ๋ฐฉ์์ ์๋นํ ๋ฆฌ์์ค ๋น์ฉ์ด ์์ต๋๋ค. reverse ๋ ์ ๋ฆฌ์คํธ์ ์๋ก์ด ๋ ธ๋๋ฅผ ๊ฐ๊ฐ push ๋ฉ์๋๋ก ํ ๋นํด์ผํฉ๋๋ค. ์ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ๊ฐ ๋ ธ๋์ next ํฌ์ธํฐ๋ฅผ ์กฐ์ํ์ฌ ๋ฆฌ์คํธ๋ฅผ ๋ค์ง์ ์ ์์ต๋๋ค. ์ฝ๋๋ ์ข ๋ ๋ณต์กํด์ง๊ฒ ์ง๋ง ์ฑ๋ฅ ๋ฉด์์ ์๋นํ ์ด์ ์ ์ป๊ฒ ๋ฉ๋๋ค.
reverse() ๋ฉ์๋๋ฅผ ์๋์ ๊ฐ์ด ์ ๋ฐ์ดํธํฉ๋๋ค.
mutating func reverse() {
tail = head
var prev = head
var current = head?.next
prev?.next = nil
// ...
}
๋จผ์ head ๋ฅผ tail ์ ํ ๋นํฉ๋๋ค. ๋ค์์ผ๋ก ๋๊ฐ์ ์ฐธ์กฐ prev ์ current ๋ฅผ ๋ง๋ค์ด ์ํ๋ฅผ ์ถ์ ํฉ๋๋ค. ์ด ์ ๋ต์ ๊ฝค ์ง๊ด์ ์ ๋๋ค. ๊ฐ ๋ ธ๋๋ ๋ฆฌ์คํธ์์ ๋ค์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๊ณ ์์ต๋๋ค. ๋ฆฌ์คํธ๋ฅผ ํ์ํ๋ฉด์ ๊ฐ ๋ ธ๋๊ฐ ์ด์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ํฉ๋๋ค.
๋ค์ด์ด๊ทธ๋จ์์ ๋ณด์ด๋ ๊ฒ์ฒ๋ผ, ์ด ๊ณผ์ ์ ๊ฝค ๋ณต์กํฉ๋๋ค. current ๋ฅผ prev ๋ก ๊ฐ๋ฆฌํค๊ฒ ๋๋ฉด ๋ฆฌ์คํธ์ ๋๋จธ์ง์ ๋ํ ๋งํฌ๋ฅผ ์๊ฒ ๋ฉ๋๋ค. ๋๋ฌธ์ ์ธ๋ฒ์งธ ํฌ์ธํฐ๋ฅผ ๊ด๋ฆฌํด์ผ ํฉ๋๋ค. reverse ๋ฉ์๋ ์๋์ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ธ์.
while current != nil {
let next = current?.next
current?.next = prev
prev = current
current = next
}
๋ฆฌ์คํธ๋ฅผ ๋ค์ง์ ๋๋ง๋ค, ๋ค์ ๋ ธ๋์ ๋ํ ์๋ก์ด ์ฐธ์กฐ๋ฅผ ์์ฑํฉ๋๋ค. ๋ชจ๋ ๊ณผ์ ์ด ๋๋๋ฉด ๋๊ฐ์ ํฌ์ธํฐ๋ฅผ ๋ค์ ๋๊ฐ์ ๋ ธ๋๋ก ์ด๋ํฉ๋๋ค.
๋ชจ๋ ์ฐธ์กฐ๋ฅผ ๋ค์ง์๋ค๋ฉด, head ๋ฅผ ๋ฆฌ์คํธ์ ๋ง์ง๋ง์ผ๋ก ์ค์ ํฉ๋๋ค. reverse ๋ฉ์๋ ๋งจ ๋์ ๋ค์์ ์ถ๊ฐํ์ธ์.
head = prev
์๋ํด๋ณด๊ธฐ
๋ค์ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์์ฑํด๋ด ์๋ค.
example(of: "reversing a list") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
print("Original list: \(list)")
list.reverse()
print("Reversed list: \(list)")
}
์๋ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of reversing a list---
Original list: 1 -> 2 -> 3
Reversed list: 3 -> 2 -> 1
์ด reverse ๋ฉ์๋์ ์๊ฐ๋ณต์ก๋๋ ์ฌ์ ํ O(n) ์ ๋๋ค. ์ด์ ์ ๋ค๋ฃจ์๋ ์ฌ์ด ๊ตฌํ๊ณผ ๋์ผํฉ๋๋ค. ํ์ง๋ง ์์ ๋ฆฌ์คํธ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์๋ก์ด Node ์ค๋ธ์ ํธ๋ฅผ ํ ๋นํ ํ์๊ฐ ์์ผ๋ฏ๋ก ์๊ณ ๋ฆฌ์ฆ์ ์ฑ๋ฅ์ ์๋นํ ํฅ์์ํฌ ์ ์์ต๋๋ค.
๋์ ๊ณผ์ 4 ํด๊ฒฐ์ฑ
์ด ๋ฌธ์ ์ ํด๊ฒฐ์ฑ ์ ๋๊ฐ์ ์ ๋ ฌ๋ ๋ฆฌ์คํธ์์ ๋ ธ๋๋ฅผ ๊ณ์ํด์ ๋ฝ์์ ์๋ก์ด ๋ฆฌ์คํธ์ ์ถ๊ฐํ๋ ๊ฒ์ ๋๋ค. ๋ ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์ด ์์ผ๋ฏ๋ก ๋ ๋ฆฌ์คํธ์ next๋ ธ๋๋ฅผ ๋น๊ตํ์ฌ ์ ๋ฆฌ์คํธ์ ๋ค์์ผ๋ก ์ถ๊ฐ๋ ๊ฒ์ด ๋ฌด์์ธ์ง ํ์ธํ ์ ์์ต๋๋ค.
์ค์ ํ๊ธฐ
๋ ๋ฆฌ์คํธ๊ฐ ๋น์๋์ง ์ฌ๋ถ๋ฅผ ์ฒดํฌํ๋ ๊ฒ์ผ๋ก ์์ํฉ๋๋ค. ์๋ ์ฝ๋๋ฅผ mergeSorted์ ์ถ๊ฐํฉ๋๋ค.
guard !left.isEmpty else {
return right
}
guard !right.isEmpty else {
return left
}
var newHead: Node<T>?
๋ง์ฝ ํ๋๊ฐ ๋น์๋ค๋ฉด ๋ค๋ฅธ ํ๋๋ฅผ ๋ฐํํฉ๋๋ค. Node ์ค๋ธ์ ํธ์ ์ ๋ ฌ๋ ๋ฆฌ์คํธ๋ฅผ ๊ฐ์ง๋๋ก ํ๋ ์ ์ฐธ์กฐ๋ฅผ ์ ์ธํฉ๋๋ค. ์ด ์ ๋ต์ left ์ right ์ ๋ ธ๋๋ค์ newHead ์ ์ ๋ ฌ๋ ์์๋ก ๋ณํฉํ๋ ๊ฒ์ ๋๋ค.
๋ค์ ์ฝ๋๋ฅผ newHead ์๋์ ์์ฑํฉ๋๋ค.
// 1
var tail: Node<T>?
var currentLeft = left.head
var currentRight = right.head
// 2
if let leftNode = currentLeft, let rightNode = currentRight {
if leftNode.value < rightNode.value {
newHead = leftNode
currentLeft = leftNode.next
} else {
newHead = rightNode
currentRight = rightNode.next
}
tail = newHead
}
- ์ถ๊ฐํ๋ ค๋ ์ ๋ชฉ๋ก์ tail ํฌ์ธํฐ๋ฅผ ๋ง๋ญ๋๋ค.
- newHead ์ ํ ๋นํ๊ธฐ ์ํด left ์ right ์ ์ฒซ๋ฒ์งธ ๋ ธ๋๋ค์ ๋น๊ตํฉ๋๋ค.
๋ณํฉํ๊ธฐ
๋ค์์ผ๋ก ์ ๋ฆฌ์คํธ๊ฐ ์ ๋ ฌ๋์๋์ง ํ์ธํ๊ธฐ ์ํด ์ถ๊ฐํ ๋ ธ๋๋ฅผ ์ ํํ์ฌ left ์ right ๋ชจ๋๋ฅผ ๋ฐ๋ณตํฉ๋๋ค. ํจ์ ๋์ ๋ค์์ ์ถ๊ฐํ์ธ์.
// 1
while let leftNode = currentLeft, let rightNode = currentRight {
// 2
if leftNode.value < rightNode.value {
tail?.next = leftNode
currentLeft = leftNode.next
} else {
tail?.next = rightNode
currentRight = rightNode.next
}
tail = tail?.next
}
- while ๋ฐ๋ณต๋ฌธ์ ๋ฆฌ์คํธ ์ค ํ๋๊ฐ ๋์ ๋๋ฌํ ๋๊น์ง ๋ฐ๋ณต๋ฉ๋๋ค.
- ์ด์ ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ ธ๋๋ค์ ๋น๊ตํ์ฌ tail ์ ์ฐ๊ฒฐํ ๋ ธ๋๋ฅผ ์ฐพ์ต๋๋ค.
์ด ๋ฐ๋ณต๋ฌธ์ currentLeft ์ currentRight ์ ์์กดํ๊ธฐ ๋๋ฌธ์ ๋ฆฌ์คํธ ์ค์ ๋ ธ๋๊ฐ ๋จ์์์ด๋ ์ข ๋ฃ๋ ์ ์์ต๋๋ค.
๋จ์ ๋ ธ๋๋ค์ ๊ด๋ฆฌํ๊ธฐ ์ํด ์๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
if let leftNodes = currentLeft {
tail?.next = leftNodes
}
if let rightNodes = currentRight {
tail?.next = rightNodes
}
๋จ์ ๋ ธ๋๋ค์ ๋ถ์ด๋ ์ฝ๋์ ๋๋ค.
๋ง๋ฌด๋ฆฌ ํ๊ธฐ ์ํด์, ์๋ก์ด ๋ฆฌ์คํธ๋ฅผ ์ด๊ธฐํํฉ๋๋ค. ๋ฆฌ์คํธ์ append ๋ insert ๋ฉ์๋๋ฅผ ์ด์ฉํด ์์๋ฅผ ์ฝ์ ํ๋ ๋์ ๋ฆฌ์คํธ์ head ์ tail ์ ์ฐธ์กฐ๋ฅผ ์ง์ ์ ์ผ๋ก ์ค์ ํ๋ฉด ๋ฉ๋๋ค.
var list = LinkedList<T>()
list.head = newHead
list.tail = {
while let next = tail?.next {
tail = next
}
return tail
}()
return list
์๋ํด๋ณด๊ธฐ
๋ค์ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์์ฑํด๋ด ์๋ค.
example(of: "merging two lists") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(1)
var anotherList = LinkedList<Int>()
anotherList.push(-1)
anotherList.push(-2)
anotherList.push(-3)
print("First list: \(list)")
print("Second list: \(anotherList)")
let mergedList = mergeSorted(list, anotherList)
print("Merged list: \(mergedList)")
}
์๋ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of merging two lists---
First list: 1 -> 2 -> 3
Second list: -3 -> -2 -> -1
Merged list: -3 -> -2 -> -1 -> 1 -> 2 -> 3
์ด ์๊ณ ๋ฆฌ์ฆ์ O(m + n)์ ์๊ฐ๋ณต์ก๋๋ฅผ ๊ฐ์ง๋๋ค. m ์ ์ฒซ๋ฒ์งธ ๋ฆฌ์คํธ์ ๋ ธ๋ ๊ฐ์์ด๊ณ n ์ ๋๋ฒ์งธ ๋ฆฌ์คํธ์ ๋ ๊ฐ์์ ๋๋ค.
๋์ ๊ณผ์ 5 ํด๊ฒฐ์ฑ
์ด ํด๊ฒฐ์ฑ ์ ๋ฆฌ์คํธ๋ฅผ ์ํํ์ฌ ์ ๊ฑฐํ๊ณ ์ ํ๋ ์์์ ์ผ์นํ๋ ๋ชจ๋ ๋ ธ๋๋ฅผ ์ญ์ ํฉ๋๋ค. ์ ๊ฑฐํ ๋๋ง๋ค ์ ํ ๋ ธ๋๋ฅผ ํ์๋ ธ๋์ ์ฌ์ฐ๊ฒฐํด์ฃผ์ด์ผ ํฉ๋๋ค. ๋ณต์กํ ์ ์์ง๋ง ์ด ๊ธฐ๋ฒ์ ์ฐ์ตํ ๊ฐ์น๋ ์ถฉ๋ถํฉ๋๋ค. ๋ง์ ์๋ฃ๊ตฌ์กฐ์ ์๊ณ ๋ฆฌ์ฆ์ด ํฌ์ธํฐ ์ฐ์ ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ ์์กดํฉ๋๋ค.
๋ช ๊ฐ์ง ๊ณ ๋ คํ ๊ฒ์ด ์์ต๋๋ค. ์ฒซ๋ฒ์งธ๋ ๋ฆฌ์คํธ์ ์๋ถ๋ถ์์ ๋ ธ๋๋ฅผ ์ง์ฐ๋ ๊ฒ์ ๋๋ค.
ํค๋๋ฅผ ์๋ผ๋ด๊ธฐ
์ฒซ๋ฒ์งธ๋ก ๊ณ ๋ คํ ์ผ์ด์ค๋ ๋ฆฌ์คํธ์ ํค๋๊ฐ ์ฌ๋ฌ๋ถ์ด ์ ๊ฑฐํ๊ณ ์ ํ๋ ๊ฐ์ ๊ฐ์ง๊ณ ์์ ๋ ์ ๋๋ค. ์๋ฅผ ๋ค์ด ์๋ ๋ฆฌ์คํธ์์ 1์ ์ ๊ฑฐํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ด ๋๋ค.
ํค๋ → 1 → 1 → 2
๊ทธ๋ ๋ค๋ฉด ์ฌ๋ฌ๋ถ์ ์๋ก์ด ํค๋๊ฐ 2๋ฅผ ๊ฐ๋ฆฌํค๋๋ก ํ ๊ฒ์ ๋๋ค.
๋ค์ ์ฝ๋๋ฅผ remove ํจ์์ ์ฝ์ ํฉ๋๋ค.
while let head = head, head.value == value {
head = head?.next
}
๋จผ์ ๋ฆฌ์คํธ์ ํค๋์ ์ ๊ฑฐํ๋ ๊ฐ์ด ์์ ๊ฒฝ์ฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. ๋์ผํ ๊ฐ์ ๊ฐ์ง ์ผ๋ จ์ ๋ ธ๋๊ฐ ์์ ์ ์์ผ๋ฏ๋ก while ๋ฐ๋ณต๋ฌธ์ ์ด์ฉํ์ฌ ๋ชจ๋ ์ ๊ฑฐํ์๋์ง ํ์ธํฉ๋๋ค.
๋ ธ๋์ ์ฐ๊ฒฐ์ ๋์ด๋ด๊ธฐ
์ฐ๊ฒฐ๋ฆฌ์คํธ์ ๊ด๋ จ๋ ๋ค๋ฅธ ๋ง์ ์๊ณ ๋ฆฌ์ฆ์ฒ๋ผ ํฌ์ธํฐ ์ฐ์ ์ฐ์ฐ์ ์ด์ฉํ์ฌ ๋ ธ๋๋ฅผ ํด์ ํฉ๋๋ค. ๋ค์ ์ฝ๋๋ฅผ remove์ ์๋์ชฝ์ ์ถ๊ฐํ์ธ์.
var prev = head
var current = head?.next
while let currentNode = current {
guard currentNode.value != value else {
prev?.next = currentNode.next
current = prev?.next
continue
}
// more to come
}
๋๊ฐ์ ํฌ์ธํฐ๋ฅผ ์ด์ฉํด ๋ฆฌ์คํธ๋ฅผ ์ํํด์ผํฉ๋๋ค. guard ๋ฌธ์ else ๋ธ๋ญ์ ๋ ธ๋๋ฅผ ์ญ์ ํด์ผํ๋ ๊ฒฝ์ฐ ๋์๋ฉ๋๋ค.
์ํ์ง ์๋ ๋ ธ๋๋ฅผ ์ฐํํ๋๋ก ๋ฆฌ์คํธ๋ฅผ ์์ ํฉ๋๋ค.
๊ณ์ ์์ ํ๊ธฐ
๋ญ ๊น๋ฐํ์๊น์? ์์ ๊ฒฝ์ฐ while ๋ฌธ์ ์ ๋ ์ข ๋ฃ๋์ง ์์ต๋๋ค. prev ์ current ํฌ์ธํฐ๋ฅผ ํจ๊ป ์ด๋ํด์ผํฉ๋๋ค. while ๋ฐ๋ณต๋ฌธ ํ๋จ guard ๋ฌธ ๋ค์ชฝ์ ๋ค์์ ์ถ๊ฐํ์ธ์.
prev = current
current = current?.next
๋ง์ง๋ง์ผ๋ก ์ฐ๊ฒฐ๋ฆฌ์คํธ์ tail ์ ์ ๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ์๋์ tail ์ด ์ ๊ฑฐํ๋ ค๋ ๊ฐ์ด ์๋ ๋ ธ๋์ผ ๊ฒฝ์ฐ ํ์ํ ์์ ์ ๋๋ค. ๋ค์์ removeAll ๋์ ์ถ๊ฐํฉ๋๋ค.
tail = prev
์๋ํด๋ณด๊ธฐ
๋ค์ ์ฝ๋๋ฅผ ํ๋ ์ด๊ทธ๋ผ์ด๋ ์๋์ ์์ฑํด๋ด ์๋ค.
example(of: "deleting duplicate nodes") {
var list = LinkedList<Int>()
list.push(3)
list.push(2)
list.push(2)
list.push(1)
list.push(1)
list.removeAll(3)
print(list)
}
์๋ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณผ ์ ์์ต๋๋ค.
---Example of deleting duplicate nodes---
1 -> 1 -> 2 -> 2
์ด ์๊ณ ๋ฆฌ์ฆ์ ๋ชจ๋ ์์๋ฅผ ์ง๋๊ฐ์ผ ํ๋ฏ๋ก ์๊ฐ๋ณต์ก๋๋ O(n) ์ ๋๋ค.
๐ ๋ฒ์ญ ์๋ฆฌ์ฆ ๋งํฌ
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
๋ง์น๋ฉฐ
์ค๋๋ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ๋๊ธ๋ก, ๋์์ด ๋์ จ๋ค๋ฉด ๊ณต๊ฐ ๋ถํ๋๋ฆฝ๋๋ค.
ํน์ ์์ ํ๊ฑฐ๋ ํผ๋๋ฐฑํ์ค ๋ด์ฉ ์๋ค๋ฉด ์ธ์ ๋ ๋๊ธ๋ก ๋ถํ๋๋ฆฝ๋๋ค.
๊ฐ์ฌํฉ๋๋ค.
๋๊ธ