Bibi's DevLog ๐Ÿค“๐ŸŽ

[Swift ์ž๋ฃŒ๊ตฌ์กฐ] 5. Queue ํ ๋ณธ๋ฌธ

ํ”„๋กœ๊ทธ๋ž˜๋ฐ/Data Structures ์ž๋ฃŒ๊ตฌ์กฐ

[Swift ์ž๋ฃŒ๊ตฌ์กฐ] 5. Queue ํ

๋น„๋น„ bibi 2022. 12. 22. 22:01

Data Structure in Swift (Queue)โ€Š-โ€ŠPart 5

swift-algorithm-club/Queue at master · kodecocodes/swift-algorithm-club

์ด ๊ธ€์€ ์œ„์˜ ๊ธ€๋“ค์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Queue ํ

ํ๋Š” ๋Œ€๊ธฐ์—ด์„ ๋œปํ•œ๋‹ค.

์‚ฌ๋žŒ๋“ค์ด ๋ฒ„์Šค๋ฅผ ํƒ€๊ธฐ ์œ„ํ•ด ์ค„์„ ์„  ๊ฒƒ์„ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค - ๋จผ์ € ์ค„์„ ์„  ์‚ฌ๋žŒ๋ถ€ํ„ฐ ์ˆœ์„œ๋Œ€๋กœ ๋ฒ„์Šค์— ํƒ„๋‹ค.

  • ์„ ํ˜• ์ž๋ฃŒ๊ตฌ์กฐ
  • ์‚ฝ์ž… ๋ฐ ์‚ญ์ œ : ์„ ์ž…์„ ์ถœ, ์ฆ‰ FIFO(First In, First Out)๋กœ ๋™์ž‘ํ•œ๋‹ค.
    • ์Šคํƒ๊ณผ์˜ ์ฐจ์ด์  : ํ๋Š” ๊ฐ€์žฅ ์˜ˆ์ „์— ๋“ค์–ด์˜จ ๊ฒƒ๋ถ€ํ„ฐ ์‚ญ์ œํ•˜๊ณ , ์Šคํƒ์€ ๊ฐ€์žฅ ์ตœ๊ทผ์— ๋“ค์–ด์˜จ ๊ฒƒ๋ถ€ํ„ฐ ์‚ญ์ œํ•œ๋‹ค.

Queue์˜ ์—ฐ์‚ฐ์ž

  • Enqueue : ๋งจ ๋’ค์— ์ƒˆ ์š”์†Œ ์‚ฝ์ž…
  • Dequeue : ๋งจ ์•ž์˜ ์š”์†Œ ์‚ญ์ œ
  • Front : ์ฒซ ๋ฒˆ์งธ ์š”์†Œ ์กฐํšŒ
  • Rear : ๋งˆ์ง€๋ง‰ ์š”์†Œ ์กฐํšŒ

Queue์˜ ์‚ฌ์šฉ

  • BFS ํƒ์ƒ‰์— ์‚ฌ์šฉ๋จ
  • ๋ฉ€ํ‹ฐํ”„๋กœ๋ ˆ์Šค์˜ CPU ์Šค์ผ€์ค„๋ง์— ์‚ฌ์šฉ๋จ
  • ๋งŽ์€ ์ž‘์—…์„ ๋น„๋™๊ธฐ๋กœ ์ˆ˜ํ–‰ํ•  ๋•Œ ์‚ฌ์šฉ๋จ (e.g. NSOperationQueue)

Queue์˜ ์ข…๋ฅ˜

  • Priority Queue ์šฐ์„ ์ˆœ์œ„ํ
    • ํ์˜ ํ™•์žฅ ๋ฒ„์ „์œผ๋กœ, ๋ชจ๋“  ์š”์†Œ๊ฐ€ ์—ฐ๊ด€๋œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๋Š”๋‹ค.
    • ํ•˜๋‚˜ ์ด์ƒ์˜ ์š”์†Œ๊ฐ€ ๊ฐ™์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์งˆ ๋•Œ๋Š”, ํ์— ์ถ”๊ฐ€๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋™์ž‘ํ•œ๋‹ค.
    • e.g. CPU ์Šค์ผ€์ค„๋ง, ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • Deque (Double Ended Queue) ๋ฑ
    • ํ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ผ๋ฐ˜ํ™”๋œ ํ˜•ํƒœ. ์‹œ์ž‘์ ๊ณผ ๋์ (Front&Rear) ๋ชจ๋‘์—์„œ ์‚ฝ์ž…๊ณผ ์‚ญ์ œ๋ฅผ ํ—ˆ์šฉํ•จ.
    • ์Šคํƒ๊ณผ ํ์˜ ์—ฐ์‚ฐ์„ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Circular Queue ์›ํ˜• ํ
    • ํ์˜ ํ™•์žฅ ๋ฒ„์ „์œผ๋กœ, ์‹œ์ž‘์ ๊ณผ ๋์ ์ด ์ด์–ด์ ธ ์žˆ๋Š” ํ˜•ํƒœ์ด๋‹ค (๋งˆ์ง€๋ง‰ ์š”์†Œ์˜ ๋‹ค์Œ ์š”์†Œ = ์ฒ˜์Œ ์š”์†Œ)
    • Ring Buffer๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
    • ํ์˜ ํฌ๊ธฐ๊ฐ€ ๊ณ ์ •๋˜์–ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ ์ข‹๋‹ค.

Queue ๊ตฌํ˜„ํ•˜๊ธฐ

Queue๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ๋Š” 4๊ฐ€์ง€ ๋ฐฉ๋ฒ•๋“ค์„ ์†Œ๊ฐœํ•œ๋‹ค.

  1. ๋ฐฐ์—ด
  2. ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ (Singly Linked List)
  3. Two Stack
  4. head ์‚ฌ์šฉํ•˜๊ธฐ

์„ค๋ช… ์—†์ด ๊ตฌํ˜„ ์ฝ”๋“œ๋งŒ ๋ณด๊ณ  ์‹ถ๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

Queue ๊ตฌํ˜„ํ•˜๊ธฐ - (1) ๋ฐฐ์—ด

struct Queue<T>: CustomStringConvertible {

    private var elements: [T] = []
    public init() {}

    var isEmpty: Bool {
        elements.isEmpty
    }

    var peek: T? {
        elements.first
    }

    var description: String {
        if isEmpty { return "Queue is empty..." }
        return "---- Queue start ----\n"
            + elements.map({"\($0)"}).joined(separator: " -> ")
            + "\n---- Queue End ----"
    }

    mutating func enqueue(_ value: T) {
        elements.append(value)
    }

    mutating func dequeue() -> T? {
        isEmpty ? nil : elements.removeFirst()
    }
}

๋ฐฐ์—ด์— ์ œ๊ณต๋˜๋Š” ๋ฉ”์„œ๋“œ๋“ค๋กœ ํ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์‚ฌ์‹ค ์ด ๋ฐฉ๋ฒ•์€ ํ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๊ธฐ๋ณด๋‹ค, ํ์˜ ๋™์ž‘์„ ํ‰๋‚ด๋ƒˆ๋‹ค๊ณ  ๋ณด๋Š” ๊ฒŒ ๋งž๋‹ค. ์‹ค์ „(์•Œ๊ณ ๋ฆฌ์ฆ˜, ๊ฐœ๋ฐœ)์— ์“ฐ๊ธฐ์— ๋„ˆ๋ฌด ๋Š๋ฆฌ๊ณ  ๋น„ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • enqueue๋Š” append()๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ O(1) ์ด๋ผ ๊ดœ์ฐฎ๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ dequeue๋Š” removeFirst() ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๋Š” O(n) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง„๋‹ค.
    • ๋ฐฐ์—ด์ด๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์— ๊ณต๋ถ€ํ•ด ๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด, ๋ฐฐ์—ด์˜ ์ฒซ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•˜๋Š”๊ฒŒ ์–ผ๋งˆ๋‚˜ ๋น„ํšจ์œจ์ ์ธ์ง€ ์•Œ ๊ฒƒ์ด๋‹ค - ๋งจ ์•ž์˜ ์š”์†Œ๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ๊ทธ ์ž๋ฆฌ๋ฅผ ์ฑ„์šฐ๊ธฐ ์œ„ํ•ด ๋‚˜๋จธ์ง€ ์š”์†Œ๋“ค์ด ๋ชจ๋‘ ํ•œ์นธ์”ฉ ์•ž์œผ๋กœ ๋‹น๊ฒจ์ ธ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ.
  • ๋˜, ๋ฐฐ์—ด์˜ ๊ฒฝ์šฐ ์š”์†Œ๋ฅผ ์ž์‹ ์˜ ํฌ๊ธฐ ์ด์ƒ์œผ๋กœ ์‚ฝ์ž…ํ•˜๋ฉด, ๊ธฐ์กด ํฌ๊ธฐ๋ณด๋‹ค 2๋ฐฐ์ •๋„์˜ ์ƒˆ ๋ฐฐ์—ด์„ ๋งŒ๋“ค์–ด ์˜ฎ๊ธฐ๋Š” ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค(= ๋ฉ”๋ชจ๋ฆฌ ์žฌํ• ๋‹น)

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— (1) ๋ฐฐ์—ด๋กœ ํ ๊ตฌํ˜„ํ•˜๊ธฐ ๋ฐฉ๋ฒ•์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์•„๋ž˜์— ์ด ๋ฌธ์ œ๋“ค์„ ๊ทน๋ณตํ•œ ๋‹ค๋ฅธ ๊ตฌํ˜„๋ฐฉ์‹์ด ์ œ์‹œ๋˜์–ด ์žˆ๋‹ค.

Queue ๊ตฌํ˜„ํ•˜๊ธฐ - (2) ์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ(Singly Linked List)

class Node<T>: CustomStringConvertible {

    var value: T
    var next: Node?

    var description: String {
        guard let next = next else { return "\(value)" }
        return "\(value) -> " + String(describing: next)
    }

    init(value: T, next: Node? = nil) {
        self.value = value
        self.next = next
    }
}

struct Queue<T>: CustomStringConvertible {

    var front: Node<T>?

    var rear: Node<T>?

    init() { }

    var isEmpty: Bool {
        return front == nil
    }

    var description: String {
        guard let front = front else { return "Empty Queue" }
        return String(describing: front)
    }

    var peek: T? {
        return front?.value
    }

        mutating private func push(_ value: T) {
        front = Node(value: value, next: front)
        if rear == nil {
            rear = front
        }
    }

    mutating func enqueue(_ value: T) {
        if isEmpty {
            self.push(value)
            return
        }

        rear?.next = Node(value: value)
        rear = rear?.next
    }

    mutating func dequeue() -> T? {
        defer {
            front = front?.next
            if isEmpty {
                rear = nil
            }
        }
        return front?.value
    }
}
  • front : ๋งจ ์•ž ๋…ธ๋“œ๋ฅผ ๋‚˜ํƒ€๋ƒ„
  • rear : ๋งจ ๋’ค ๋…ธ๋“œ๋ฅผ ๋‚˜ํƒ€๋ƒ„
  • enqueue : ๋งจ ๋’ค์— ์š”์†Œ ์ถ”๊ฐ€. O(1)
    • rear ์ฐธ์กฐ๊ฐ’์„ ํ™œ์šฉํ•ด ๊ทธ๋ƒฅ ๋งจ ๋งˆ์ง€๋ง‰์— ์ƒˆ ์š”์†Œ๋ฅผ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.
  • dequeue : ๋งจ ์•ž์˜ ์š”์†Œ ์‚ญ์ œ. O(1)
    • ์—ญ์‹œ front ์ฐธ์กฐ๊ฐ’์„ ํ™œ์šฉํ•ด ๊ทธ๋ƒฅ ๋งจ ๋งˆ์ง€๋ง‰์— ์ƒˆ ์š”์†Œ๋ฅผ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค๋งŒ enqueue์ž‘์—…์—์„œ ๋งค๋ฒˆ ๋™์  ๋ฉ”๋ชจ๋ฆฌํ• ๋‹น ์‹œ๊ฐ„์ด ์†Œ์š”๋œ๋‹ค.

Queue ๊ตฌํ˜„ํ•˜๊ธฐ - (3) Stack ๋‘ ๊ฐœ๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ (two stacks)

์ผ๋ช… ํˆฌ์Šคํƒ์ด๋ผ ๋ถˆ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์™ผ์ชฝ ์Šคํƒ๊ณผ ์˜ค๋ฅธ์ชฝ ์Šคํƒ์„ ๊ฐ€์ง€๊ณ  ํ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

https://user-images.githubusercontent.com/67407678/208900218-1a01fdc3-362d-4008-835b-42d6d3901d02.png

  • Left Stack ์™ผ์ชฝ ์Šคํƒ
    • ๋ชจ๋“  dequeue ์—ฐ์‚ฐ์„ ์—ฌ๊ธฐ์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • Right Stack ์˜ค๋ฅธ์ชฝ ์Šคํƒ
    • ๋ชจ๋“  enqueue ์—ฐ์‚ฐ์„ ์—ฌ๊ธฐ์—์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค.

ํˆฌ์Šคํƒ ๋ฐฉ์‹์˜ ํŠน์ง•

  • ๋ฐฐ์—ด์— ๊ธฐ๋ฐ˜ํ•œ ๊ตฌํ˜„๋ฐฉ์‹์ž„
    • ๋ฐฐ์—ด์€ ์—ฐ์†์ ์ธ ์ธ๋ฑ์Šค์— ๋”ฐ๋ผ ๋ชจ๋“  ๊ฐ’์ด ์ €์žฅ๋จ
    • ๋”ฐ๋ผ์„œ ๋งŽ์€ ์–‘์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒซ ์•ก์„ธ์Šค์— ์บ์‹œ์— ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค
  • Circular Queue์™€ ๋‹ฌ๋ฆฌ ํฌ๊ธฐ ์ œํ•œ์ด ์—†๋‹ค
struct TwoStackQueue<T>: CustomStringConvertible {

    var leftStack: [T] = []
    var rightStack: [T] = []

    var isEmpty: Bool {
        leftStack.isEmpty && rightStack.isEmpty
    }

    var peek: T? {
        leftStack.isEmpty ? rightStack.first : leftStack.last
    }

    mutating func enqueue(_ element: T) {
        rightStack.append(element)
    }

    mutating func dequeue() -> T? {

        if isEmpty {
            return nil
        }

        if leftStack.isEmpty {
            leftStack = rightStack.reversed()
            rightStack.removeAll()
        }

        return leftStack.removeLast()
    }
}

extension TwoStackQueue {

    var description: String {

        if isEmpty {
            return "Queue is empty..."
        }
        var allElements: [T] = []
        if leftStack.isEmpty == false {
            allElements.append(contentsOf: leftStack.reversed())
        }
        allElements.append(contentsOf: rightStack)

        return "---- Queue start ----\n"
            + allElements.map({"\($0)"}).joined(separator: " -> ")
            + "\n---- Queue End ----"
    }
}

๋™์ž‘์›๋ฆฌ

  • enqueue()
    • append(): Right Stack์˜ ๋ฐฐ์—ด์— ๊ฐ’์„ ์ถ”๊ฐ€ํ•œ๋‹ค. O(1) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง
  • dequeue()
    • ๋งŒ์•ฝ Left Stack๊ณผ Right Stack์ด ๋ชจ๋‘ ๋น„์–ด์žˆ๋‹ค๋ฉด, ์–ธ๋”ํ”Œ๋กœ์šฐ ์ƒํ™ฉ์ด ๋œ๋‹ค.
    • ๋งŒ์•ฝ Left Stack์ด ๋น„์–ด์žˆ๋‹ค๋ฉด, Right Stack์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ˆœ์„œ๋ฅผ ๋’ค์ง‘์–ด Left Stack์— ๊ฐ€์ ธ์˜ค๊ณ  Right Stack์„ ๋น„์šด๋‹ค.
    • removeLast() : Left Stack์˜ ๋งจ ๋ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

Queue ๊ตฌํ˜„ํ•˜๊ธฐ - (4) head๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„

์ฐธ๊ณ  : https://github.com/kodecocodes/swift-algorithm-club/tree/master/Queue#a-more-efficient-queue

(1)์˜ ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„ํ•œ ๋ฐฉ์‹์—์„œ, dequeue์— ํ•ด๋‹นํ•˜๋Š” removeFirst() ๊ฐ€ O(n) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ์—ˆ๋‹ค.

๋ฐ˜๋Œ€๋กœ ๋งํ•˜๋ฉด removeFirst() ๋Œ€์‹  ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ dequeue๋ฅผ ํ•œ๋‹ค๋ฉด ๊ดœ์ฐฎ๋‹ค๋Š” ์ด์•ผ๊ธฐ์ด๋‹ค.

์•„๋ž˜ ๊ตฌํ˜„๋ฐฉ์‹์€ ๋ฐฐ์—ด๋กœ ๋งŒ๋“  ํ์—์„œ ์•ž์˜ ์š”์†Œ๋ฅผ ์ง์ ‘ ‘์ง€์šฐ๋Š”’ ๋Œ€์‹ , nil ์„ ํ• ๋‹นํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

  • ๋งจ ์•ž์˜ ์š”์†Œ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” head ๋ฅผ ๋งŒ๋“ ๋‹ค
  • ์š”์†Œ๋ฅผ ์ง€์šฐ๋Š” ๋Œ€์‹ , ๊ทธ ์ž๋ฆฌ์— nil ์„ ํ• ๋‹นํ•˜๊ณ  head ์— 1์„ ๋”ํ•œ๋‹ค
    • O(1) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • ํ์—์„œ head์˜ ์œ„์น˜๊ฐ€ ์ผ์ • ์ธ๋ฑ์Šค ์ด์ƒ์ด ๋˜๋ฉด (= nil์ด ์–ด๋Š์ •๋„ ์ด์ƒ ๋งŽ์•„์ง€๋ฉด), nil์ด ์•„๋‹Œ ์š”์†Œ๋“ค์„ ์•ž์œผ๋กœ ์˜ฎ๊ฒจ์˜จ๋‹ค.
    • ์ด ์ž‘์—…์€ O(n) ์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๋Š”๋‹ค.
public struct Queue<T> {
      fileprivate var array = [T?]()
      fileprivate var head = 0

      public var isEmpty: Bool {
            return count == 0
      }

      public var count: Int {
            return array.count - head
      }

      public mutating func enqueue(_ element: T) {
            array.append(element)
      }

      public mutating func dequeue() -> T? {
            guard head < array.count, let element = array[head] else { return nil }

            array[head] = nil
            head += 1

            let percentage = Double(head)/Double(array.count)
            if array.count > 50 && percentage > 0.25 {
              array.removeFirst(head)
              head = 0
            }

            return element
      }

      public var front: T? {
            if isEmpty {
              return nil
            } else {
              return array[head]
            }
      }
}
  • head : ๋ฐฐ์—ด์—์„œ ๋งจ ์•ž์— ์žˆ๋Š” ๊ฐ์ฒด์˜ ์ธ๋ฑ์Šค๋ฅผ ๋‚˜ํƒ€๋ƒ„
    • head ๋Š” array ์˜ ์ „์ฒด ํฌ๊ธฐ๋ณด๋‹ค ์ž‘์•„์•ผ ํ•œ๋‹ค
  • enqueue() : ๋งจ ๋’ค์— ์ƒˆ ์š”์†Œ๋ฅผ ๋ถ™์ž„. ๋‹ฌ๋ผ์ง„ ์  ์—†์Œ. O(1)
  • dequeue() : ๊ฐ€์žฅ ๋‹ฌ๋ผ์ง„ ๋ถ€๋ถ„. O(1)
    • dequeue์—ฐ์‚ฐ์„ ํ•˜๋ฉด ๋ฐฐ์—ด์˜ ๋งจ ์•ž์˜ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•ด์•ผ ํ•œ๋‹ค.
    • ์ด๋•Œ ์ง์ ‘ ์‚ญ์ œํ•˜๋Š” ๋Œ€์‹ , head ๋กœ ๋งจ ์•ž ๊ฐ์ฒด์˜ ์ธ๋ฑ์Šค๋ฅผ ์•Œ์•„๋‚ด๊ณ , ๊ฑฐ๊ธฐ์— nil์„ ํ• ๋‹นํ•œ๋‹ค.
    • ๊ทธ๋Ÿฌ๋ฉด ์‚ญ์ œ๋œ ์š”์†Œ์˜ ๋‹ค์Œ ์š”์†Œ๊ฐ€ ์ฒซ ์š”์†Œ๊ฐ€ ๋˜๋ฏ€๋กœ head += 1 ์„ ํ•ด์ค€๋‹ค.

๐Ÿค” dequeue๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉด nil์ด ์ ์  ๋งŽ์•„์ ธ์„œ array ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ณต๊ฐ„์ด ์ปค์ง€๋Š”๋ฐ ๋น„ํšจ์œจ์ ์ด์ง€ ์•Š๋‚˜์š”?

  • ๊ทธ๋ž˜์„œ ์ฃผ๊ธฐ์ ์œผ๋กœ array ์—์„œ nil๋“ค์„ ์ณ๋‚ด๋Š” ์žฌ๋ฐฐ์น˜ ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ๊ทธ ์—ญํ• ์„ ํ•œ๋‹ค.
let percentage = Double(head)/Double(array.count)
if array.count > 50 && percentage > 0.25 {
      array.removeFirst(head)
      head = 0
}
  • ์กฐ๊ฑด1 : array์˜ 25% ์ด์ƒ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ์žˆ์„ ๋•Œ
  • ์กฐ๊ฑด2 : array ์˜ ํฌ๊ธฐ๊ฐ€ 50์ด ๋„˜์„ ๋•Œ
    • array ํฌ๊ธฐ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ปค์กŒ์„ ๋•Œ๋งŒ ์กฐ๊ฑด ํ™•์ธ ๋ฐ ์žฌ๋ฐฐ์น˜ํ•˜๋„๋ก ํ•จ
    • 50์ด๋ผ๋Š” ์ˆซ์ž๋Š” ๊ฐ์ž ์ƒํ™ฉ์— ๋”ฐ๋ผ ์กฐ์ •ํ•˜๋ฉด ๋œ๋‹ค.
  • ์žฌ๋ฐฐ์น˜์ž‘์—… : removeFirst(k:) ๋กœ, ๋ฐฐ์˜†์˜ ์•ž์—์„œ๋ถ€ํ„ฐ head ๊ฐœ ๋งŒํผ์˜ ์š”์†Œ๋“ค์„ ์—†์• ๊ณ , head ๋ฅผ 0์œผ๋กœ ์žฌ์„ค์ •ํ•œ๋‹ค
    • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•ž์— ์ž๋ฆฌ๋ฅผ ์ฐจ์ง€ํ•˜๋˜ nil ๊ฐ์ฒด๋“ค์ด ์‚ฌ๋ผ์ง„๋‹ค.
    • head ๋Š” ์ฒซ ์š”์†Œ์˜ ์ธ๋ฑ์Šค์ด๋ฉด์„œ ๋™์‹œ์— ์•ž์˜ nil ์ธ ์š”์†Œ๋“ค์˜ ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ๋„ ํ•˜๊ธฐ ๋•Œ๋ฌธ.

(์ฐธ๊ณ ) Circular Queue ๊ตฌํ˜„ํ•˜๊ธฐ - Ring Buffer

์ผ๋ฐ˜Queue๊ฐ€ ์•„๋‹Œ Circular Queue๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

๋งŒ์•ฝ ๊ณ ์ •๋œ ์‚ฌ์ด์ฆˆ์˜ ํ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, Circular Queue๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‹ค.

struct RingBufferQueue<T>: CustomStringConvertible {

    private var elements: [T?]
    private var front = -1
    private var rear = -1

    init(count: Int) {
        elements = Array(repeating: nil, count: count)
    }

    var isEmpty: Bool {
        front == -1 && rear == -1
    }

    var isFull: Bool {
        ((rear + 1) % elements.count) == front
    }

    var description: String {
        if isEmpty { return "Queue is empty..." }
        return "---- Queue start ----\n"
            + elements.map({String(describing: "\($0)")}).joined(separator: " -> ")
            + "\n---- Queue End ----\n"
    }

    var peek: T? {
        if isEmpty { return nil }
        return elements[front]
    }
}

extension RingBufferQueue {

    // to enqueue an element
    mutating func enqueue(_ element: T) -> Bool {

        // if queue is empty
        if front == -1 && rear == -1 {
            front = 0
            rear = 0
            elements[rear] = element
            return true
        }

        if isFull {
            print("QUEUE IS FULL")
            return false
        }

        rear = (rear + 1) % elements.count
        elements[rear] = element
        return true
    }
}

extension RingBufferQueue {

    // to dequeue an element
    mutating func dequeue() -> T? {

        if isEmpty {
            print("QUEUE IS EMPTY")
            return nil
        }

        // if queue has only single element
        if front == rear {
            defer {
                elements[front] = nil
                front = -1
                rear = -1
            }
            return elements[front]
        }

        defer {
            elements[front] = nil
            front = (front + 1) % elements.count
        }
        return elements[front]
    }
}
  • enqueue : O(1)
  • dequeue : O(1)