[Swift][λ²μ] μ€μννΈμ μλ£κ΅¬μ‘°μ μκ³ λ¦¬μ¦ - μΉμ 2. κΈ°μ΄ μλ£κ΅¬μ‘° - μ±ν°4~5. μ€ν, μ€ν λμ κ³Όμ
Raywenderlich.com μμ λμ¨ Data Structures & Algorithms in Swift μ± μ λ°λͺ¨ 곡κ°λ³Έμ λ²μνμμ΅λλ€. μ¦κ²κ² λ΄μ£ΌμΈμ.
https://www.raywenderlich.com/books/data-structures-algorithms-in-swift
μΉμ 2. κΈ°μ΄ μλ£κ΅¬μ‘° Elementary Data Structure
μ±ν° 4. μ€ν Stacks
μ€νμ μ΄λ κ³³μλ μμ΅λλ€. μ€νμ΄ μλ μΌλ°μ μΈ μμλ₯Ό λ€μ΄λ³΄κ² μ΅λλ€.
- ν¬μΌμ΅
- μ± λ€
- μ’ μ΄
- μ§ν
μ€ν stack μλ£κ΅¬μ‘°λ κ°λ μ μΌλ‘ κ°μ²΄μ 물리μ μ€νκ³Ό λμΌν©λλ€. μ΄λ€ νλͺ©μ μ€νμ λ£μΌλ©΄ μ€νμ 맨 μμ λμ΄κ² λ©λλ€. μ€νμ μ΄λ€ νλͺ©μ μ κ±°νλ€λ©΄ νμ κ°μ₯ μμ μλ νλͺ©μ΄ μ κ±°λ©λλ€.
μ’μ μμ: ν¬μΌμ΄ν¬κ° μμΈ μ€ν, λμ μμ: κ°μ₯ μμ μλ ν¬μΌμ΄ν¬λ§ λ¨Ήμ μ μλ€λ κ².
μ€νμ μμ Stack operations
μ€νμ μ μ©νκ³ λ λ무λ κ°λ¨ν©λλ€. μ€νμ ꡬμΆνλ μ£Όμ λͺ©νλ λ°μ΄ν°λ₯Ό μ κ·Όνλ λ°©λ²μ μ μ©νλ κ²μ λλ€.
μ€νμλ λ κ°μ§μ νμ μμ λ§ μμ΅λλ€.
- νΈμ push: μ€νμ μ΅μλ¨μ μμ μΆκ°νκΈ°
- ν pop: μ€νμ μ΅μλ¨ μμλ₯Ό μ κ±°νκΈ°
μΈν°νμ΄μ€λ₯Ό μ΄ λκ°μ§ μμ μΌλ‘ μ ννλ κ²μ μλ£κ΅¬μ‘°μ ν λ°©ν₯μμλ§ μΆκ°νκ±°λ μ κ±°ν μ μλ€λ κ²μ λλ€. μ»΄ν¨ν° κ³Όνμμ μ€νμ LIFO(νμ μ μΆ) μλ£κ΅¬μ‘°λ‘λ μλ €μ Έ μμ΅λλ€. κ°μ₯ λ§μ§λ§μ νΈμPush λ μμκ° κ°μ₯ λ¨Όμ νPop λμ΄ λκ°μ§λλ€.
μ€νμ νλ‘κ·Έλλ° μ λΆμΌμμ λλλ¬μ§κ² μ¬μ©λ©λλ€. λͺ κ°μ§λ₯Ό λμ΄νμλ©΄,
- iOSλ λ€λΉκ²μ΄μ μ€νμ μ¬μ©νμ¬ λ·°μ»¨νΈλ‘€λ¬λ₯Ό λ·° μνμΌλ‘ νΈμνκ±°λ νν©λλ€.
- λ©λͺ¨λ¦¬ ν λΉμ μν€ν μ²λ 벨μμ μ€νμ μ¬μ©ν©λλ€. μ§μλ³μλ₯Ό μ μ₯νλ λ©λͺ¨λ¦¬λ μ€νμ μ¬μ©νμ¬ κ΄λ¦¬ν©λλ€.
- λ―Έλ‘μμ κΈΈμ μ°Ύλ κ²κ³Ό κ°μ λΆν μ 볡 μκ³ λ¦¬μ¦(Search and conquer algorithms)μμ μ€νμ μ¬μ©νμ¬ μμΆμ μ νΈλ¦¬νκ² ν©λλ€.
ꡬν Implementation
μ΄ μ±ν°μ μ€νν° νλ μ΄κ·ΈλΌμ΄λλ₯Ό μ΄κ³ , νλ μ΄κ·ΈλΌμ΄λμ Source ν΄λμ Stack.swift λΌλ νμΌμ λ§λλλ€. νμΌ μμ μλ μ½λλ₯Ό μμ±ν©λλ€.
public struct Stack<Element> {
private var storage: [Element] = []
public init() { }
}
extension Stack: CustomDebugStringConvertible {
public var debugDescription: String {
"""
----top----
\(storage.map { "\($0)" }.reversed().joined(separator: "\n"))
-----------
"""
}
}
μμ μ€νμ λ°±μ μ€ν 리μ§(backing storage)λ₯Ό μ μνμμ΅λλ€. μ€νμ μ ν©ν μ€ν λ¦¬μ§ μ νμ μ ννλ κ²μ λ§€μ° μ€μν©λλ€. λ°°μ΄μ append μ popLast λ₯Ό μ΄μ©νμ¬ νμͺ½ λμμ μμμκ°μ μ½μ κ³Ό μμ κ° μ΄λ£¨μ΄μ§λ―λ‘ νμ€ν μ νμ λλ€. μ΄ λ κ°μ§ μμ μ μ¬μ©νλ©΄ μ€νμ νμ μ μΆ νΉμ±μ΄ λμ± μ©μ΄ν΄μ§λλ€.
CustomDebugStringConvertible νλ‘ν μ½μ νμν debugDescription μ ν¨μ νΈμΆ 체μΈμ μν΄μ 3κ°μ§ μμ μ ν΄μΌν©λλ€.
- storage.map { "\\($0)" } λ‘ λ¬Έμμ΄μ 맀ννλ λ°°μ΄ λ§λ€κΈ°
- reversed() λ₯Ό μ΄μ©νμ¬ μ΄μ λ°°μ΄μ λ€μ§λ μλ‘μ΄ λ°°μ΄μ λ§λ€κΈ°
- joined(separator:) λ₯Ό μ΄μ©νμ¬ λ°°μ΄μ λ¬Έμμ΄λ‘ λ³ν©. "\\n" κ°νλ¬Έμλ₯Ό μ΄μ©νμ¬ λ°°μ΄μ μμλ₯Ό λΆλ¦¬
μ΄λ κ² ν΄μ λλ²κΉ μ μ¬μ©ν μ μλ μΆλ ₯κ°λ₯ν Stack νμ μ ννμ΄ μμ±λ©λλ€.
νΈμμ ν μμ push and pop operations
Stackμ μλ λκ°μ§ μμ μ μΆκ°νμΈμ
public mutating func push(_ element: Element) {
storage.append(element)
}
@discardableResult
public mutating func pop() -> Element? {
storage.popLast()
}
λ§€μ° κ°λ¨νμ£ ! νλ μ΄κ·ΈλΌμ΄λμμ μλ μ½λλ₯Ό μμ±ν©λλ€.
example(of: "using a stack") {
var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
print(stack)
if let poppedElement = stack.pop() {
assert(4 == poppedElement)
print("Popped: \(poppedElement)")
}
}
μλμ κ°μ΄ μΆλ ₯λμ΄μΌ ν©λλ€.
---Example of using a stack---
----top----
4
3
2
1
-----------
Popped: 4
push μ pop μ λ λ€ μκ°λ³΅μ‘λκ° O(1) μ λλ€.
λΉνμ μμ Non-essential operations
μ€νμ λ μ½κ² μ¬μ©ν μ μλ μ μ©ν μμ λ€μ΄ μμ΅λλ€. Stack.swift μμ μλ μ½λλ₯Ό Stackμ μΆκ°νμΈμ.
public func peek() -> Element? {
storage.last
}
public var isEmpty: Bool {
peek() == nil
}
μ€ν μΈν°νμ΄μ€μλ μ’ μ’ peek μμ μ΄ ν¬ν¨λ©λλ€. peek μ μμ μ½ν μΈ λ₯Ό λ³κ²½νμ§ μκ³ μ€νμ μλ¨ μμλ₯Ό μ΄ν΄λ³΄λ κ²μ λλ€.
μ μμλ‘ μ’μ΅λλ€ Less is more
μ€νμ μ€μννΈ μ½λ μ νλ‘ν μ½μ μ μ©ν μ μμμ§ κΆκΈν κ²μ λλ€. μ€νμ λͺ©μ μ λ°μ΄ν°μ μ κ·Όνλ λ°©λ²μ κ°μ§μλ₯Ό μ ννλ κ²μ λλ€. Collection κ³Ό κ°μ νλ‘ν μ½μ μ±ννλ κ²μ λ°λ³΅μ(iterator)μ μλ첨μ(subscript)λ₯Ό ν΅ν΄ λͺ¨λ μμλ₯Ό λ ΈμΆνλ―λ‘ μ€νμ λͺ©μ μ λ°νλ κ²μ λλ€. μ΄ κ²½μ°μλ λ μ μ κ²μ΄ μ’μ΅λλ€.
μ κ·Ό μμλ₯Ό 보μ₯νκΈ° μν΄ κΈ°μ‘΄μ λ°°μ΄μ μ·¨ν΄μ μ€νμΌλ‘ λ³ννκ³ μΆμ μ μμ΅λλ€. λΉμ°ν λͺ¨λ λ°°μ΄ μμλ₯Ό λ°λ³΅νμ¬ κ° μμλ₯Ό push νλ κ²μ κ°λ₯ν©λλ€.
private μ μ₯μλ₯Ό μ€μ νλ μμ±μλ₯Ό μμ±ν μ μμΌλ―λ‘, μλ μ½λλ₯Ό μ€ν ꡬνμ μΆκ°ν©λλ€.
public init(_ elements: [Element]) {
storage = elements
}
μλ μμ λ₯Ό λ©μΈ νλ μ΄κ·ΈλΌμ΄λμ μΆκ°ν©λλ€.
example(of: "initializing a stack from an array") {
let array = ["A", "B", "C", "D"]
var stack = Stack(array)
print(stack)
stack.pop()
}
μ μ½λλ λ¬Έμμ΄ μ€νμ μμ±νκ³ μ΅μλ¨ μμ “D”λ₯Ό λ΄λ³΄λ λλ€. μ€μννΈ μ»΄νμΌλ¬λ λ°°μ΄λ‘λΆν° μμμ νμ μ μΆλ‘ ν μ μμΌλ―λ‘ Stack<String> λμ μ Stack μ μ¬μ©ν μ μμ΅λλ€.
ν λ¨κ³ λ λμκ° λ°°μ΄ λ¦¬ν°λ΄μ ν΅ν΄ μ€νμ μ΄κΈ°νν μ μλλ‘ λ§λ€ μ μμ΅λλ€. μλλ₯Ό μ€ν ꡬν μ μΆκ°νμΈμ.
extension Stack: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: Element...) {
storage = elements
}
}
λ©μΈ νλ μ΄κ·ΈλΌμ΄λλ‘ λμκ° μλ μ½λλ₯Ό μΆκ°ν©λλ€.
example(of: "initializing a stack from an array literal") {
var stack: Stack = [1.0, 2.0, 3.0, 4.0]
print(stack)
stack.pop()
}
μ μ½λλ Double μ€νμ μμ±νκ³ μ΅μλ¨ κ° 4.0μ λ΄λ³΄λ λλ€. λ€μ λ§νμλ©΄ νμ μΆλ‘ μ ν΅ν΄ Stack<Double> λ₯Ό μ λ ₯νμ§ μμλ λ©λλ€.
μ€νμ νΈλ¦¬μ κ·Έλνλ₯Ό κ²μsearchνλ λ¬Έμ μ λ§€μ° μ€μν©λλ€. λ―Έλ‘μμ κΈΈμ μ°Ύλ κ²μ μμν΄λ³΄μΈμ. μΌμͺ½, μ€λ₯Έμͺ½, μ§μ§μ μ νν΄μΌλ λλ§λ€ ν μ μλ λͺ¨λ κ²°μ μ μ€νμ μ μ₯ν μ μμ΅λλ€. λ§λ€λ₯Έ 골λͺ©μ λλ¬νλ©΄ μ€νμμ λ§μ§λ§ κ²°μ μ λ΄λ³΄λ(pop)μΌλ‘μ¨ μμΆμ ν μ μκ³ , λ€λ₯Έ λ§λ€λ₯Έ 골λͺ©μ λλ¬νκ±°λ νμΆνκΈ° μ κΉμ§ μ΄λ₯Ό κ³μν μ μμ΅λλ€.
ν΅μ¬ μμ½ Key points
- μ€νμ LIFO, νμ μ μΆ μλ£κ΅¬μ‘°μ΄λ€.
- λ§€μ° λ¨μνμ§λ§ μ€νμ λ§μ λ¬Έμ λ€μ ν΅μ¬ μλ£κ΅¬μ‘°μ΄λ€.
- μ€νμ λκ°μ§ νμ μμ μΌλ£, μμλ₯Ό μΆκ°νλ push λ©μλμ μμλ₯Ό μ κ±°νλ pop λ©μλκ° μλ€.
μ±ν° 5. μ€ν λμ κ³Όμ Stack Challenges
μ€νμ λλΌμΈ μ λλ‘ λ§μ μ΄ν리μΌμ΄μ μ΄ μλ λ¨μν μλ£κ΅¬μ‘°μ λλ€.
starter νλ‘μ νΈλ₯Ό μ΄μ΄μ μλ λμ κ³Όμ λ€μ νμΈν μ μμ΅λλ€.
첫λ²μ§Έ λμ κ³Όμ : λ°°μ΄ λ°μ Reverse an Array
μ€νμ μ¬μ©νμ¬ λ°°μ΄μ μμλ₯Ό μμμΌλ‘ μΆλ ₯νλ ν¨μλ₯Ό λ§λμΈμ.
λλ²μ§Έ λμ κ³Όμ : κ΄νΈ μ§ νμΈνκΈ° Balance the parentheses
κ΄νΈμ μ§μ΄ λ§λμ§ νμΈν©λλ€. μ£Όμ΄μ§ λ¬Έμμ΄μμ ( μ ) κ° μλμ§ νμΈνκ³ , μ§μ΄ λ§μΌλ©΄ true μ λ°νν©λλ€.
// 1
h((e))llo(world)() // balanced parentheses
// 2
(hello world // unbalanced parentheses
ν΄κ²°μ± Solutions
λμ κ³Όμ 1 ν΄κ²°μ±
μ€νμ μ£Ό μ΄μ© μ¬λ‘ μ€ νλλ μμΆμ μ μ©μ΄νκ² νλ κ²μ λλ€. κ°λ€μ μνμ€λ₯Ό μ€νμ νΈμνκ³ , μμ°¨μ μΌλ‘ ννλ©΄ κ°λ€μ μμμΌλ‘ μ»κ²λ©λλ€.
func printInReverse<T>(_ array: [T]) {
var stack = Stack<T>()
for value in array {
stack.push(value)
}
while let value = stack.pop() {
print(value)
}
}
λ Έλλ₯Ό μ€νμ νΈμνλ©΄ μκ°λ³΅μ‘λλ O(n) μ λλ€. μ€νμ μμλ₯Ό ννμ¬ κ°μ μΆλ ₯νλ κ² μμ O(n) μ λλ€. μ΅μ’ μ μΌλ‘ μ μκ³ λ¦¬μ¦μ μκ° λ³΅μ‘λλ O(n) μ΄ λ©λλ€.
μ€ν 컨ν μ΄λλ₯Ό ν¨μ μμ ν λΉνμμΌλ―λ‘ κ³΅κ°λ³΅μ‘λ λΉμ©μΌλ‘λ O(n) μ΄ λλλ€.
π λ©λͺ¨: νμ€ λΌμ΄λΈλ¬λ¦¬μμ μ 곡νλ reversed() λ©μλλ₯Ό νΈμΆνμ¬ λ°°μ΄μ λ°μ ν μ μμ΅λλ€. λ°°μ΄μμ μ΄ λ©μλλ O(1) μ μκ°κ³Ό 곡κ°λ³΅μ‘λμ λλ€. μλνλ©΄ μλ³Έ μ½λ μ μμ λ°μ λ λ·°λ§ μμ±νκΈ° λλ¬Έμ λλ€. λ§μ½ μμ΄ν μ μννκ³ λͺ¨λ μμλ₯Ό μΆλ ₯νλ©΄ μκ°λ³΅μ‘λλ O(n)μ΄ λκ³ κ·Έ λμ 곡κ°λ³΅μ‘λλ O(1)μ΄ λ©λλ€.
λμ κ³Όμ 2 ν΄κ²°μ±
λ¬Έμμ΄μμ κ΄νΈμ μ§μ΄ λ§λμ§ νμΈνκΈ° μν΄μ, λ¬Έμμ΄μ κ° λ¬Έμλ₯Ό νμΈν΄μΌ ν©λλ€. μ¬λ κ΄νΈλ₯Ό λ§λλ©΄ μ€νμ νΈμνκ³ , λ°λλ‘ λ«λ κ΄νΈλ₯Ό λ§λλ©΄ μ€νμ νν©λλ€.
μ½λλ μλμ κ°μ΅λλ€.
func checkParentheses(_ string: String) -> Bool {
var stack = Stack<Character>()
for character in string {
if character == "(" {
stack.push(character)
} else if character == ")" {
if stack.isEmpty {
return false
} else {
stack.pop()
}
}
}
return stack.isEmpty
μ μκ³ λ¦¬μ¦μ μκ°λ³΅μ‘λλ O(n) μ λλ€. μ¬κΈ°μ nμ λ¬Έμμ΄ λ΄μ λ¬Έμ κ°―μμ λλ€. μ΄ μκ³ λ¦¬μ¦μ Stack μλ£κ΅¬μ‘°μ μ¬μ©μΌλ‘ 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
λ§μΉλ©°
μ€λλ μ½μ΄μ£Όμ μ κ°μ¬ν©λλ€.
κΆκΈν μ μ΄ μλ€λ©΄ λκΈλ‘, λμμ΄ λμ ¨λ€λ©΄ κ³΅κ° λΆνλ립λλ€.
νΉμ μμ νκ±°λ νΌλλ°±νμ€ λ΄μ© μλ€λ©΄ μΈμ λ λκΈλ‘ λΆνλ립λλ€.
κ°μ¬ν©λλ€.
λκΈ