博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Heap(堆结构/优先队列)-Swift实现
阅读量:6251 次
发布时间:2019-06-22

本文共 4011 字,大约阅读时间需要 13 分钟。

特性

堆结构很像二叉树,堆也是一个近似树形结构,堆的每个节点也最多有左、右两个孩子,但是堆实质是存储在数组中的结构,所以他和二叉树只是近似的有某些共同的特性。

  • 第一特性,堆结构是存储在数组中的。
  • 堆通过 priority 优先事项进行排序,可以分为,max-priority(最高优先级)、和 max-priority(最低优先级)两种
  • 二叉搜索树中,有left<parent<right 的特性,但是在堆中,只是只能保证孩子一定是小于或大于父节点的。
  • 二叉树在存储的过程中需要更多的内存,因为节点需要存储指向父节点,子节点等的指针,但是堆不需要,他存储在数组中
  • 二叉树中的一些特别树,如红黑树,AVL树等,删除,插入,及搜索的多度都很快,但是,堆结构的搜索相对来说会慢很多,但是堆结构对于查找,最大或者最小等需求时,查找速度是很快的。
  • 堆有一个很重要的特性,就是只有在上一层完全满之后,才能到下一层来进行存储,不允许中间某个节点的子节点为空,因为是通过数组存储的嘛

前面说过堆结构实际存储在数组中,他具体的形式如下

从上面的图中可以推导出,一个重要的公式: 节点 node 的孩子在数组中的位置: 左孩子:index = 2 * i + 1 右孩子:index = 2 * i + 2 其中i为当前节点n在数组中的下标

插入及删除

堆结构的插入及删除操作的基本思路如下:

  • 插入: 插入时一定是从最后面开始插入,类似入队操作,插入后,用新节点和父节点比,如果优先级大于父节点,则和父节点交互位置后,继续和新的父节点比较,依次类推
  • 删除:删除通常为删除最大的节点,即根节点,过程为,先将根节点和最后面的节点互换位置后,在删除最后面的节点,即原来的根节点,然后用根节点和子节点向下进行比较,如果小于子节点,则互换位置,依次类推。 时刻谨记,堆结构是存储在数组中的。

实现

struct Heap
{ ///存放元素的数组 var elements: [Element] //比较两个元素大小的方法 let priorityFunction: (Element, Element) -> Bool init(elements: [Element] = [], priorityFunction: @escaping (Element, Element) -> Bool) { // 1 // 2 self.elements = elements self.priorityFunction = priorityFunction // 3 buildHeap() // 4 } mutating func buildHeap() { for index in (0 ..< count / 2).reversed() { // 5 siftDown(index) // 6 } } var isEmpty : Bool { return elements.isEmpty } var count : Int { return elements.count } func peek() -> Element? { return elements.first } func isRoot(_ index: Int) -> Bool { return (index == 0) } ///当前节点的左孩子 func leftChildIndex(of index: Int) -> Int { return (2 * index) + 1 } ///当前节点的右孩子 func rightChildIndex(of index: Int) -> Int { return (2 * index) + 2 } ///当前节点的父节点 func parentIndex(of index: Int) -> Int { return (index - 1) / 2 } //插入 mutating func equeue(_ element: Element) { elements.append(element) siftUP(elementAtIndex: elements.count - 1) } //删除 mutating func dequeue() -> Element? { //判空 guard !isEmpty else { return nil } //将第一个节点和最后一个节点交换位置 swapElement(at: 0, with: count - 1) //删除原本的第一个,现在的最后一个 elements.removeLast() guard !isEmpty else { return nil } //向下判断,新的节点是不是优先级最高的节点 return nil }}private extension Heap { func isHigherPriority(firstIndex: Int, secondIndex: Int) -> Bool{ return priorityFunction(elements[firstIndex], elements[secondIndex]) } func highestPriorityIndex(of parentIndex: Int, and childIndex: Int) -> Int { guard childIndex < count && isHigherPriority(firstIndex: childIndex, secondIndex: parentIndex) else { return parentIndex } return childIndex } func highestPriorityIndex(for parent: Int) -> Int { return highestPriorityIndex(of: highestPriorityIndex(of: parent, and: leftChildIndex(of: parent)), and: rightChildIndex(of: parent)) } mutating func swapElement(at firstIndex: Int, with secondIndex: Int) { guard firstIndex != secondIndex else { return } elements.swapAt(firstIndex, secondIndex) } mutating func siftDown(_ elementIndex: Int) { //从当前节点及子节点中找出优先级最高的节点 let highestIndex = highestPriorityIndex(for: elementIndex) //如果当前节点就是优先级最高的节点,直接放回 if highestIndex == elementIndex { return } //如果不是优先级最高的节点,和优先级最高的节点对换位置 swapElement(at: elementIndex, with: highestIndex) //从新的节点开始递归的向下判断优先级 siftDown(highestIndex) } mutating func siftUP(elementAtIndex: Int) { //获得父节点的索引 let parentIndex = self.parentIndex(of: elementAtIndex) //如果当前节点不是根节点,比较当前节点和父节点的优先级 guard !isRoot(elementAtIndex), isHigherPriority(firstIndex: elementAtIndex, secondIndex: parentIndex) else { return } //如果当前节点的优先级高于父节点,兑换位置 swapElement(at: elementAtIndex, with: parentIndex) //递归的从新的父节点开始向上比较 siftUP(elementAtIndex: parentIndex) }}复制代码

转载地址:http://ngysa.baihongyu.com/

你可能感兴趣的文章
函数声明和函数表达式
查看>>
Matlab基本函数-conj函数
查看>>
linux常用命令 3
查看>>
SharePoint 2013 托管导航 无法被开启的解决办法
查看>>
初识Java Servlet
查看>>
Test1
查看>>
JS图片切换代码合集
查看>>
Aundit使用记录文档
查看>>
原型 、原型链和对象是怎么实现继承的
查看>>
layui中select切换数据_layui 下拉框 动态获取数据
查看>>
佳能hdr_内置HDR功能 佳能5D3特色拍摄功能解析
查看>>
matlab和python转换_将MATLAB代码转换为Python:Python类型和操作顺序
查看>>
jmeter3000用户压测_jmeter集群压测搭建
查看>>
转子接地保护原理_发变组保护动作逻辑
查看>>
hive中groupby优化_面试必备技能-HiveSQL优化
查看>>
uni 页面加载完毕_HTML页面生命周期
查看>>
c语言机票座位预定系统_趁东京奥运!日航要免费送5万张国内机票!给非日本居民...
查看>>
创业冲突的五种解决方法是_冲突管理的五种策略
查看>>
lsmw中文显示乱码_中文注释不能在keil 4/5中正常显示——都是方框或乱码?
查看>>
hcg值小于0.1_【原理】JavaScript 中 0.1 + 0.2 为什么不等于 0.3?
查看>>