使用Kotlin实现Java的优先队列PriorityQueue

前言

上周在面试时,偶然一个算法用到了优先队列思想。我只懂效果不懂实现,当时感觉和堆排序的思想差不多。今天深入源码,自己又实现一遍加深印象。

源码有什么

  1. 具有Queue和Collection集合和Queue队列的性质
  2. 可以保证每次取出的元素都是最值(默认是最小,可以自己设置)
  3. 内部采用推排序思想,上浮siftUp和下沉siftDown
  4. 存储采用可变数组(和ArrayList一样),默认大小是11,刚开始每次*2+2,后面每次加一半(size+=size>>2)

如何实现一个优先队列

  1. 队列最基本的offer,peek,poll
  2. 集合最基本的isEmpty,toString,size
  3. 供内部使用的siftUp,siftDown,grow

代码实现

个人有写算法加注释的习惯,看不懂私聊

import java.util.*
import kotlin.math.max

fun main() {
    val queue = MyPriorityQueue().apply {
        repeat(10) {
            offer(Random().nextInt(100))
        }
    }
    while (queue.isNotEmpty()) {
        println(queue.poll())
    }
}

class MyPriorityQueue {
    // 保存元素,方便实现泛型,默认大小是11
    private var array = Array(11) { 0 }

    // 当前数目
    private var size = 0

    // 增
    fun offer(value: Int) {
        if (size == array.size) {
            grow(size + 1)
        }
        array[size++] = value
        siftUp(size - 1, value)
    }


    // 看队头
    fun peek(): Int {
        return if (size == 0) -1 else array[0]
    }

    // 取对头
    fun poll(): Int {
        if (size == 0) {
            return -1
        }
        val result = array[0]
        array[0] = array[size - 1]
        size--
        siftDown(0, array[0])
        return result
    }

    // 没有size方法
    fun size() = size

    // 没有isEmpty方法
    fun isEmpty() = size == 0

    fun isNotEmpty() = size > 0

    // 上浮,默认最小在上面
    private fun siftUp(index: Int, value: Int) {
        // 在上面选个大的和当前交换,没有退出
        var i = index
        while (i > 0) {
            val parent = (i - 1) / 2
            if (array[parent] <= value) {
                break
            }
            array[i] = array[parent]
            i = parent
        }
        array[i] = value
    }

    // 下沉,默认最大在下面
    private fun siftDown(index: Int, value: Int) {
        // 选出子节点最小的一个,没有则退出
        var i = index
        // 当至少存在左子节点时
        while (i * 2 + 1 < size) {
            // 找出最小的子节点下标
            val minChild = if (i * 2 + 2 >= size || array[i * 2 + 1] <= array[i * 2 + 2]) i * 2 + 1 else i * 2 + 2
            // 如果最小的还是比父节点大,退出
            if (array[minChild] >= value) {
                break
            }
            array[i] = array[minChild]
            i = minChild
        }
        array[i] = value
    }

    // 扩容机制,小于64,*2+2,大于,+>>2
    private fun grow(minCapacity: Int) {
        var newCapacity = array.size + if (array.size < 64) array.size + 2 else array.size / 2
        // 在一次添加大量元素才可能用到
        newCapacity = max(newCapacity, minCapacity)
        array = Arrays.copyOf(array, newCapacity)
    }

    // 重写toString方法
    override fun toString() = StringBuilder().apply {
        append("[")
        for (i in 0 until size) {
            append(
                if (i == 0) array[i] else " ${array[i]}"
            )
        }
        append("]")
    }.toString()
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值