GREEN.1229 2021. 5. 18. 09:38

안녕하십니까. 그린입니다🟢

이번 포스팅에서는 스택에 대해 알아보고 Swift로 구현해보겠습니다🧑🏻‍💻

 

스택

: 후입선출 자료구조 (LIFO)

 -> 기능이 제한된 배열 (푸쉬/팝/픽의 세가지 역할밖에 못함)

 -> 순서가 중요할때 가장 뒤 순서의 데이터를 꺼냄으로 배열 크기와 상관없이 항상 O(1)의 시간 복잡도를 가짐 (배열보다 효율적)

 -> 중간 데이터 삭제 불가능

Swift로 스택 구현하기

import Foundation

struct Stack<T> {
    var stack: [T] = []
    
    // 초기화 시 아무 값이 주어지지 않을때 동작하는 초기화
    init() {}
    
    // 초기화 시 값이 주어질때 동작하는 초기화
    init(_ element: [T]) {
        stack = element
    }
    
    // 데이터 저장
    mutating func push(_ element: T) {
        stack.append(element)
    }
    
    // 데이터 추출함과 동시에 제거
    mutating func pop() -> T? {
        return stack.popLast()
    }
    
    // 데이터 추출만
    func peek() -> T? {
        return stack.last
    }
    
    // 스택이 비었는지 판별
    func isEmpty() -> Bool {
        return stack.isEmpty
    }
    
    // 스택의 갯수 카운트
    func count() -> Int? {
        return stack.count
    }
}

// 스택을 출력할때 커스텀한 설명을 추가하는 프로토콜
extension Stack: CustomStringConvertible {
    var description: String {
        return stack.description + "이 스택에 들어있습니다."
    }
}

// 스택 초기화 후 반복문 없이 배열로 스택을 넣을때 사용하는 프로토콜
extension Stack: ExpressibleByArrayLiteral {
    init(arrayLiteral elements: T...) {
        for element in elements {
            stack.append(element)
        }
    }
}

var firstStack: Stack = Stack<Int>()
var secondStack: Stack = Stack<Int>([1, 2, 3, 4])
var thirdStack: Stack = Stack<Int>()

firstStack = [2, 4, 6, 8]
thirdStack.push(10)
thirdStack.push(20)
print("\(firstStack)" + "\n" + "\(secondStack)" + "\n" + "\(thirdStack)")

위와 같이 다양하게 스택의 초기화를 두어 편하게 사용할 수 있습니다.

스택의 push와 pop은 구조체의 프로퍼티에 값을 추가/삭제하여 변경됨으로 꼭 mutating 키워드를 붙여 프로퍼티를 변경할 수 있는 메서드라는걸 명시해줘야합니다.

또한, CustomStringConvertible 프로토콜을 채택해 스택을 출력 시 원하는 설명을 커스텀하게 설정할 수 있습니다.

마찬가지로 CustomDebugStringConvertible 프로토콜을 채택해 아래와 같이 사용하면 디버그 메시지에 대해 커스텀하게 설정할 수 있습니다.

extension Stack: CustomDebugStringConvertible {
    var debugDescription: String {
        return stack.debugDescription + "이 스택의 디버그 설명입니다."
    }
}

마지막으로 초기화 시 값을 주어주지 않거나 매번 반복해서 값을 하나씩 주어주기 불편할때 ExpressibleByArrayLiteral 프로토콜을 사용할 수 있습니다.

공식문서에도 나와있듯이 init 초기화 시 arrayLiteral을 통해 주어진 배열리터럴에서 배열을 만듭니다.

만들어진 배열로 스택에 들어가게 초기화를 구현할 수 있습니다.

이 속성을 사용하기위해 해당 프로토콜을 채택하여야합니다.