Swift Queue

描述

队列是一种只可以在队尾进行插入操作并且在队头进行删除操作的列表。这保证了你插入队列的第一个元素也是你出列的第一个元素。先进先出。

为什么需要队列呢?在许多算法中你想添加对象到一个临时的列表,随后再取出。通常添加和删除这些对象的顺序是重要的。

队列提供了先进先出(FIFO)的顺序。

下面是入队:

queue.enqueue(10)

现在队列是[10],添加下一个数字到队列中:

queue.enqueue(3)

现在队列是[10, 3],再添加一个数字:

queue.enqueue(57)

队列是[10, 3, 57],然后我们进行出列:

queue.dequeue()

这次返回10,因为这是第一个被插入的数据。队列现在时[3, 57],每个元素都向前移动了一位。

queue.dequeue()

这次是3,下次出列是57。如果队列为空,出列操作就是返回空或是返回一个错误信息。


代码实现

下面是一个Swift简单的实现队列。通过封装数组实现入列,出列和查看队头元素。

public struct Queue<T> {
    fileprivate var array = [T]()
    
    public var isEmpty: Bool {
        return array.isEmpty
    }
    
    public var count: Int {
        return array.count
    }
    
    public mutating func enqueue(_ element: T) {
        array.append(element)
    }
    
    public mutating func dequeue() -> T? {
        if isEmpty {
            return nil
        } else {
            return array.removeFirst()
        }
    }
    
    public var front: T? {
        return array.first
    }
}

这个队列可以工作,但是不是最优的方案。

入列是O(1),因为添加到数组的末尾总是需要相同的时间,无论数组的大小。你也许会疑惑为什么是O(1),并且是一个恒定的操作时长。因为在Swift中数组的最后总是有一些空余的空间。如果我们做一下操作:

var queue = Queue<String>()
queue.enqueue("Ada")
queue.enqueue("Steve")
queue.enqueue("Tim")

数组实际是这样的:

[ "Ada", "Steve", "Tim", xxx, xxx, xxx ]

xxx是保留未填入的内存,添加一个新的元素就是覆写数组中一个未使用的位置。

这导致了拷贝内存从一个地方到另一个地方,耗时都是一样的。

在数组的末尾只有有限的一些未使用的空间。当最后一个xxx被使用后,如果你还要添加元素,数组就需要调整大小来获得更多的空间。

调整大小包括分配新内存并将所有现有数据复制到新数组。 这是一个相对较慢的O(n)的过程。 由于偶尔会发生这种情况,所以将新元素添加到数组末尾的时间大体仍然是O(1)或O(1)“摊销”。

出列的情况是不同的。出列,我们移除数组的第一个元素,总是O(n)的操作,因为它需要数组中的所有元素在内存中移位。

在我们的例子中,将“Ada”出列,然后拷贝“Steve”到“Aad”的位置,以此类推:

before   [ "Ada", "Steve", "Tim", "Grace", xxx, xxx ]
                   /       /      /
                  /       /      /
                 /       /      /
                /       /      /
 after   [ "Steve", "Tim", "Grace", xxx, xxx, xxx ]

在内存中移动这些元素是O(n)的操作。所以我们简单实现的队列,入列是效率好的,但是出列还需要提升。


更好的方案

为了使出列也有效率,我们也可以保留一些空余的空间在数组的头部。主要思想是,无论何时我们出列一个元素,我们不移动数组中元素,而是在出列的位置标记一个空。这样当出列“Ada”,数据时这样的:

[ xxx, "Steve", "Tim", "Grace", xxx, xxx ]

当出列“Steve”后,数组是:

[ xxx, xxx, "Tim", "Grace", xxx, xxx ]

因为数组前部的空位置是永远不会使用的,所有可以定期地将剩余的元素移动到前面(Trim)。

[ "Tim", "Grace", xxx, xxx, xxx, xxx ]

Trim这个操作是O(n),但是这个操作在一段时间内只会执行一次,所以总体上出列是O(1)。

我们可以重新定义新的队列:

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 precentage = Double(head) / Double(array.count)
        if array.count > 50 && precentage > 0.25 {
            array.removeFirst(head)
            head = 0
        }
        return element
    }
    
    public var front: T? {
        if isEmpty {
            return nil
        } else {
            return array[head]
        }
    }
}

数组保存的是T?类型而不是T,因为我们需要在数组中标记一个元素当它为空时。Head就是数组中第一个对象的索引。

大都数新的功能在dequeue()。当我们出列一个元素,首先设置array[head]为nil以从数组中移除该元素。随后,我们增加head,因为下一个元素成为了队首。

如果我们从不移除数组前部那些空的占位的元素,数组会越来越大,为了定期整理数组,做了以下操作:

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

[译]https://github.com/raywenderlich/swift-algorithm-club/tree/master/Queue

转载于:https://www.cnblogs.com/horo/p/6685756.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值