实现一个线程安全的栈

这里使用数组来存储栈的数据。不足之处在于本例中的Stack可以无限扩容,更好的是初始化时候指定一个最大容量,防止不断扩容申请内存导致内存不够的问题。这里的线程安全使用一个串行队列来保证,实际上也可以通过加锁或者信号量甚至自旋锁来解决。

struct Stack<Element> {

    private var items: [Element]

    private var queue = DispatchQueue(label: "StackOperationQueue")

    public init(capacity: Int = 10) {
items = [Element]()
items.reserveCapacity(capacity)
} mutating public func push(item: Element) {
queue.sync {
items.append(item)
}
} mutating public func pop() -> Element? {
var item: Element?
queue.sync {
item = items.removeLast()
}
return item
}
}

实现一个线程安全的队列

// 存储数据的双向链表节点
class DoubleLinkNode<Element> {
var previous: DoubleLinkNode?
var next: DoubleLinkNode?
let val: Element?
init(val: Element?) {
self.val = val
}
//声明==运算符,便于判断两个节点是否相等
static func ==(left: DoubleLinkNode<Element>, right: DoubleLinkNode<Element>) -> Bool {
//最准确的做法是判断内存地址是否相同
let leftPointValue = Unmanaged<AnyObject>.passUnretained(left).toOpaque()
let rightPointValue = Unmanaged<AnyObject>.passUnretained(right).toOpaque()
return leftPointValue == rightPointValue
}
} /*
1.使用双向链表实现队列结构,声明空的head/last哨兵节点简化双向链表操作;
2.使用串行队列保证线程安全,实际上也可以通过加锁的方式实现线程安全;
3.对于生产者-消费者模型,这里可以使用semaphore来实现,当队列为空的时候,让线程休眠,当有元素入队的时候唤醒一个线程继续执行任务。
*/
struct Queue<Element> {
//声明串行队列,将操作放在串行队列中,保证线程安全
private var queue = DispatchQueue(label: "QueueOperationQueue") let firstNode: DoubleLinkNode<Element>
let lastNode: DoubleLinkNode<Element> public init(capacity: Int = 20) {
firstNode = DoubleLinkNode(val: nil)
lastNode = DoubleLinkNode(val: nil)
firstNode.next = lastNode
lastNode.previous = firstNode
} /// 入队操作
mutating public func enqueue(item: Element) {
queue.sync {
let node = DoubleLinkNode<Element>(val: item)
let tmp = firstNode.next
firstNode.next = node
node.previous = firstNode
node.next = tmp
tmp?.previous = node
}
} /// 出队操作
mutating public func dequeue() -> Element? {
guard let previous = lastNode.previous, !(firstNode == previous) else { return nil }
var node: DoubleLinkNode<Element>? = nil
queue.sync {
node = lastNode.previous
node?.next = nil
node?.previous = nil
let tmp = node?.previous
lastNode.previous = tmp
tmp?.next = lastNode
}
return node?.val
}
}

swift实现线程安全的栈和队列的更多相关文章

  1. Swift 算法实战之路:栈和队列

    这期的内容有点剑走偏锋,我们来讨论一下栈和队列.Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列.笔者觉得最实用的实现方法是使用数组,本期主要内容有: 栈和 ...

  2. 算法与数据结构(二) 栈与队列的线性和链式表示(Swift版)

    数据结构中的栈与队列还是经常使用的,栈与队列其实就是线性表的一种应用.因为线性队列分为顺序存储和链式存储,所以栈可以分为链栈和顺序栈,队列也可分为顺序队列和链队列.本篇博客其实就是<数据结构之线 ...

  3. [Swift]LeetCode232. 用栈实现队列 | Implement Queue using Stacks

    Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of ...

  4. swift语言之多线程操作和操作队列(下)———坚持51天吃掉大象(写技术文章)

    欢迎有兴趣的朋友,参与我的美女同事发起的活动<51天吃掉大象>,该美女真的很疯狂,希望和大家一起坚持51天做一件事情,我加入这个队伍,希望坚持51天每天写一篇技术文章.关注她的微信公众号: ...

  5. java集合详解(附栈,队列)

    1 集合 1.1 为什么会出现集合框架 [1] 之前的数组作为容器时,不能自动拓容 [2] 数值在进行添加和删除操作时,需要开发者自己实现添加和删除. 1.2 Collection接口 1.2.1 C ...

  6. 什么是“堆”,"栈","堆栈","队列",它们的区别?

    堆:什么是堆?又该怎么理解呢? ①堆通常是一个可以被看做一棵树的数组对象.堆总是满足下列性质: ·堆中某个节点的值总是不大于或不小于其父节点的值: ·堆总是一棵完全二叉树. 将根节点最大的堆叫做最大堆 ...

  7. 纯数据结构Java实现(2/11)(栈与队列)

    栈和队列的应用非常多,但是起实现嘛,其实很少人关心. 但问题是,虽然苹果一直宣传什么最小年龄的编程者,它试图把编程大众化,弱智化,但真正的复杂问题,需要抽丝剥茧的时候,还是要 PRO 人士出场,所以知 ...

  8. 堆”,"栈","堆栈","队列"以及它们的区别

    如果你学过数据结构,就一定会遇到“堆”,"栈","堆栈","队列",而最关键的是这些到底是什么意思?最关键的是即使你去面试,这些都还会问到, ...

  9. 【PHP数据结构】栈和队列的应用

    通过栈和队列的学习,我们似乎会感觉到其实数据结构还是非常简单的嘛.当然,这只是一个开始,我们从顺序表.链表开始,到现在的栈和队列,其实都是为了将来在铺路.在树和图的遍历算法中,都可以见到栈和队列的身影 ...

随机推荐

  1. docker 内时区和宿主机差8个小时,怎么办?

    docker run -d -it --name tt -e TZ=Asia/Shanghai -p : api 使用-e参数指定时区

  2. asp.net大文件上传解决方案

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传  ...

  3. HOJ 2315 Time(模拟)

    Description Kim是一个掌控时间的大师.不同于一般人,他习惯使用秒来计算时间.如果你问他现在是几点,他会告诉你现在是今天的xxxx秒.Mik想要考考Kim.他想知道从某一天的00:00:0 ...

  4. 手动写Makefile编译Android NDK的so

    之所以摒弃NDK,是因为NDK编译出来的so太大,而且导出表总有一些没用的符号.而且手动编译的话,可以得到编译过程中间的.i和.s文件,可以删除一些没用的汇编代码.现在代码列出来:我的NDK C的代码 ...

  5. 170829-关于AOP面向切面编程

    1.AOP概念:Aspect Oriented Programming 面向切面编程 2.作用:本质上来说是一种简化代码的方式 继承机制 封装方法 动态代理  …… 3.情景举例 ①数学计算器接口[M ...

  6. 安装 windows 2008 解决 gpt 分区问题

    新服务器,4T硬盘,U盘安装Windows Server 2008 R2. 把2008的镜像用UltraISO写入U盘. 安装到分区那块,主分区200G,剩余分区系统自动给分为: 2T + 剩余 两块 ...

  7. Java中的BigDecimal类和int和Integer总结

    前言 我们都知道浮点型变量在进行计算的时候会出现丢失精度的问题.如下一段代码: System.out.println(0.05 + 0.01); System.out.println(1.0 - 0. ...

  8. JS - 事件循环和任务队列

    栈.堆和队列 栈:函数调用形成栈 堆:对象的内容分配在堆中 队列:一个 JavaScript 运行时包含了一个待处理的消息队列.在事件循环期间依次处理队列中的消息 事件循环 之所以称之为事件循环,是因 ...

  9. Linux基础—saltstack运维工具学习

    一.saltstack简介 1.saltstack是什么 系统管理员日常会进行大量的重复性操作,例如安装软件,修改配置文件,创建用户,批量执行命令等,如果主机数量庞大,单靠人工维护实在让人难以忍受. ...

  10. Swiper轮播手动后不动

    最近项目首页轮播图用了Swiper轮播,今天突然发现轮播图动画初始正常但是手动换过之后就不动了,解决方法有两种,具体根据采用的情况为准: 1.autoplayDisableOnInteraction: ...