美文网首页算法
算法:手动实现大顶堆、小顶堆

算法:手动实现大顶堆、小顶堆

作者: 某非著名程序员 | 来源:发表于2021-01-13 19:10 被阅读0次

在刷LeetCode时,经常看到Java系统函数PriorityQueue。swift中没有,只能手动构造一个了。堆相关题目还是不少,要好好掌握。

提供一个父类

class PriorityQueue {
    var heap = [Int]()

    init(_ heap:[Int]) {
        self.heap = heap
    }
    
    func count() -> Int {
        return heap.count
    }
    
    func top() -> Int? {
        return self.heap.first
    }
    
    func isEmpty() -> Bool {
        return self.heap.count == 0
    }
}

大顶堆

//大顶堆
class MaxPriorityQueue:PriorityQueue {
    
    override init(_ heap:[Int]) {
        super.init(heap)
        
        if heap.count == 0 {
            return
        }
        //构建大顶堆
        for i in (0...heap.count/2).reversed() {
            heapAdjust(&self.heap, i, heap.count)
        }
    }
    
    //上浮法:把新元素插入堆尾,向上逐层比较,上浮到合适的位置
    func add(_ val:Int) {
        self.heap.append(val)//插入尾部
        
        var childIndex = self.heap.count-1
        var parentIndex = (childIndex-1)/2
        while parentIndex>=0 && heap[childIndex]>heap[parentIndex] {
            heap.swap(childIndex, parentIndex)
            childIndex = parentIndex
            parentIndex = (childIndex-1)/2
        }
        
    }
    
    //弹出堆顶元素:用尾部元素放到堆顶,调整
    func poll() -> Int {
        if self.heap.count == 0 {
            return 0
        }
        let topVal = self.heap.first!
        
        self.heap[0] = self.heap.last!
        self.heap.removeLast()
        if heap.count>1 {//0或1个不用调整
            heapAdjust(&self.heap, 0, self.heap.count)
        }
        
        return topVal
    }
    
    //大顶堆
    func heapAdjust(_ array:inout [Int], _ parent:Int,_ length:Int) {
        var parentIndex = parent
        let temp = array[parentIndex]
        var child = 2*parentIndex+1//2n+1:左孩子,2n+2:右孩子
        //把最小的数据放在大于孩子节点的位置
        while child<length {
            //取左右孩子节点的最大节点
            if child+1<length && array[child]<array[child+1]{
                child += 1
            }
            if temp>array[child]{//父节点大于左右孩子节点
                break
            }
            array[parentIndex] = array[child]
            parentIndex = child
            
            child = 2*child+1
        }
        array[parentIndex] = temp
    }
    
}
  1. 初始化时:堆的调整。只要处理一半的数据。把大的数据浮到顶部。在堆排序中也有用到。
  2. add:添加元素。
    上浮法:把新元素插入堆尾,向上逐层比较,上浮到合适的位置
  3. poll:弹出元素
    弹出堆顶元素:用尾部元素放到堆顶,调整

小顶堆

//小顶堆
class MinPriorityQueue:PriorityQueue {
    
    override init(_ heap:[Int]) {
        super.init(heap)
        
        if heap.count == 0 {
            return
        }
        //构建大顶堆
        for i in (0...heap.count/2).reversed() {
            heapAdjust(&self.heap, i, heap.count)
        }
    }
    
    //上浮法:把新元素插入堆尾,向上逐层比较,上浮到合适的位置
    func add(_ val:Int) {
        self.heap.append(val)//插入尾部
        
        var childIndex = self.heap.count-1
        var parentIndex = (childIndex-1)/2
        while parentIndex>=0 && heap[childIndex]<heap[parentIndex] {
            heap.swap(childIndex, parentIndex)
            childIndex = parentIndex
            parentIndex = (childIndex-1)/2
        }
        
    }
    
    //弹出堆顶元素:用尾部元素放到堆顶,调整
    func poll() -> Int {
        if self.heap.count == 0 {
            return 0
        }
        let topVal = self.heap.first!
        
        self.heap[0] = self.heap.last!
        self.heap.removeLast()
        if heap.count>1 {//0或1个不用调整
            heapAdjust(&self.heap, 0, self.heap.count)
        }
        
        return topVal
    }
    
    //小顶堆
    func heapAdjust(_ array:inout [Int], _ parent:Int,_ length:Int) {
        var parentIndex = parent
        let parentVal = array[parentIndex]
        var child = 2*parentIndex+1//2n+1:左孩子,2n+2:右孩子
        //把最小的数据放在大于孩子节点的位置
        while child<length {
            //取左右孩子节点的最大节点
            if child+1<length && array[child]>array[child+1]{
                child += 1
            }
            if parentVal<array[child]{//父节点大于左右孩子节点
                break
            }
            array[parentIndex] = array[child]
            parentIndex = child
            
            child = 2*child+1
        }
        array[parentIndex] = parentVal
    }
}

小顶堆与大顶堆类似,调整堆时判断条件需要改变下。

总结

  1. 堆在算法中用的比较多。下面推荐几道算法题,上面代码可以直接应用。
    295. 数据流的中位数
    621. 任务调度器
    659. 分割数组为连续子序列
    767. 重构字符串
    1046. 最后一块石头的重量
    1202. 交换字符串中的元素

相关文章

  • 算法:手动实现大顶堆、小顶堆

    在刷LeetCode时,经常看到Java系统函数PriorityQueue。swift中没有,只能手动构造一个了。...

  • 剑指offer 数据流中的中位数

    建立大顶堆和小顶堆

  • 大顶堆生成、新增、删除、排序javascript实现

    大顶堆小顶堆的概念和使用本文不赘述,使用js实现一个大顶堆的创建,新增,删除以及利用大顶堆排序

  • 堆在java中的应用--PriorityQueue

    堆的特点 堆是一种完全二叉树的模拟,堆一般是基于数组的实现,堆分大顶堆和小顶堆,大顶堆就是堆顶是最大的数据,然后子...

  • C 语言实现堆排序 (Heap Sort)

    堆排序是一种基于「堆」这一数据结构的排序算法。堆是一种近似完全二叉树的结构,分为大顶堆和小顶堆这两种。 大顶堆:子...

  • 数据流的中位数

    使用双pq,一个大顶堆装小于middle的数,一个小顶堆装大于middle的数。大顶堆与小顶堆之间元素个数差不能大...

  • 堆--求中位数

    针对动态数据,求排序后处于中间的数据思路:维护两个堆,一个大顶堆,一个小顶堆。大顶堆中存储前半部分数据,小顶堆中存...

  • 堆调整算法

    堆调整算法 思路 算法将获取到一组数据的最大值(针对大顶堆)或最小值(针对小顶堆)。 基本思想 通过堆排序的调整算...

  • 堆排序

    算法原理 首先将数组构建成按照排序方式转换成大顶堆(从小到大)或小顶堆(从大到小) 将堆顶元素和最后一个元素交换位...

  • 堆排序的实现

    使用大顶锥实现升序排序,二叉堆的详细操作见以前的文章 步骤如下: 先构建大顶堆 然后循环删除堆顶元素(交互首尾元素...

网友评论

    本文标题:算法:手动实现大顶堆、小顶堆

    本文链接:https://www.haomeiwen.com/subject/jbrywktx.html