【scala原理系列】PriorityQueue原理用法示例源码详解

本文详细介绍了Scala中的PriorityQueue数据结构,重点解析了其基于堆的实现原理,以及高效的操作特性。PriorityQueue在插入和删除元素时具有O(log n)的时间复杂度,适用于优先级处理的场景。文章还涵盖了方法总结和示例代码,帮助理解其使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【scala原理系列】PriorityQueue原理用法示例源码详解

源自专栏《SparkML:scala原理系列目录

概览

这个类使用堆实现了优先队列。在创建时,必须提供一个隐式的 Ordering[A] 对象来对元素进行排序。

如果在 PriorityQueue 的排序中有多个元素具有相同的优先级,那么不能保证 dequeue 或 dequeueAll 方法返回元素的顺序。

特别地,这个类不保证按先进先出的方式返回元素,尽管从类名 Queue 可以错误地推断出这种行为。

只有 dequeue 和 dequeueAll 方法会按照优先顺序(同时从堆中删除元素)返回元素。标准集合方法,如 drop、iterator 和 toString,将按照最方便的顺序删除或遍历堆。

因此,打印一个 PriorityQueue 不会显示元素的优先顺序,虽然优先级最高的元素将首先被打印出来。要按顺序打印元素,必须复制 PriorityQueue(例如使用 clone 方法),然后逐个出队:

@example {
  {
  {

val pq = collection.mutable.PriorityQueue(1, 2, 5, 3, 7)

println(pq)                  // 元素可能不是按顺序的

println(pq.clone.dequeueAll) // 打印 Vector(7, 5, 3, 2, 1)

}}}

原理

PriorityQueue(优先队列)是一种数据结构,它是基于堆(Heap)实现的。堆是一种完全二叉树,其中每个节点的值都大于等于其子节点的值(最大堆),或者每个节点的值都小于等于其子节点的值(最小堆)。

PriorityQueue 的原理是通过维护一个堆来保持元素的有序性。在 PriorityQueue 中,每个元素都具有优先级,并且较高优先级的元素会被先处理。内部实现使用数组来存储元素,根据元素的优先级进行堆调整(上浮和下沉操作),以确保堆的性质得到保持。

PriorityQueue 中,插入元素时,新元素被放置在数组的末尾,并根据其优先级进行上浮操作,将其移动到正确的位置以满足堆的性质。删除元素时,位于数组开头的元素(即根节点)具有最高优先级,因此被移除,并用数组末尾的元素替换。然后,根据其优先级进行下沉操作,将新元素移到正确的位置以满足堆的性质。这样就保证了优先队列中始终可以快速访问和删除具有最高优先级的元素。

通过使用堆数据结构,PriorityQueue 可以在插入和删除操作中具有较高的效率。插入元素的时间复杂度为O(log n),其中n是队列中的元素数量。删除最高优先级元素的时间复杂度也为O(log n)。由于堆的性质,访问具有最高优先级的元素的时间复杂度为O(1)。

因此,PriorityQueue 提供了一种有效地处理具有优先级的元素的方式,并保持它们的有序性。这在许多应用中非常有用,例如任务调度、事件处理等场景。

方法总结

方法名 描述
toQueue 将优先队列转换为普通队列。
self 返回代理类中的原始优先队列实例。
self = PriorityQueueProxy.this.self.clone() 克隆代理类中的原始优先队列实例。
reverseIterator 返回一个以与正常顺序相反的顺序返回所有元素的迭代器。
reverse 返回优先队列的反转版本。新的优先队列具有与原始队列相同的元素,但是顺序相反。
result(): PriorityQueue[A] 返回一个已经进行堆调整的优先队列。
result 返回该构建器的结果(优先队列本身)。
p_swap(a: Int, b: Int) 交换数组中的两个位置的元素。
p_size0_=(s: Int) 设置数组的大小。
p_size0 获取数组的大小。
p_ensureSize(n: Int) 确保数组的大小至少为n。
p_array 获取数组的引用。
next(): A 返回迭代器的下一个元素。
newBuilder 创建一个新的构建器,用于构建优先队列。
length 返回优先队列中的元素数量。
hasNext 检查迭代器是否还有下一个元素。
enqueue(elems: A*) 将多个元素添加到队列中。
dequeueAll 返回一个包含队列中所有元素的新集合。
dequeue() 返回并删除队列中的最高优先级元素。
clear() 清空队列,使其为空。
+= 将单个元素插入队列。
++ 将另一个可遍历对象中的所有元素添加到队列。

示例代码

package com.test

import scala.collection.mutable.PriorityQueue

object PriorityQueueDemo {
   
  def main(args: Array[String]): Unit = {
   
    // 创建一个优先队列,并指定元素的排序方式(按照整数大小降序排列)
    val pq = PriorityQueue[Int]()(Ordering.Int.reverse)

    // 添加元素到优先队列
    pq += 5
    pq += 2
    pq += 8

    // 将可遍历对象中的所有元素添加到优先队列
    pq ++= Seq(10, 3, 1)

    // 打印队列中的所有元素
    println(" Priority Queue: " + pq.toList)
    
    // 有序打印队列中的所有元素
    println("Sorted Priority Queue: " + pq.clone().dequeueAll)
    
    // 弹出最高优先级的元素并打印
    val highestPriorityElement = pq.dequeue()
    println("Highest Priority Element: " + highestPriorityElement)

    // 返回队列中最高优先级的元素(最小堆)但不移除
    val peekedElement = pq.head
    println("Peeked Element: " + peekedElement)

    // 清空队列
    pq.clear()

    // 检查队列是否为空
    val isEmpty = pq.isEmpty
    println("Is Queue Empty? " + isEmpty)
  }
}
//Priority Queue: List(1, 3, 2, 10, 5, 8)
//Sorted Priority Queue: Vector(1, 2, 3, 5, 8, 10)
//Highest Priority Element: 1
//Peeked Element: 2
//Is Queue Empty? true

中文源码分析

import generic._

/** 
  * 这个类使用堆实现了优先队列。
  * 在创建时,必须提供一个隐式的 Ordering[A] 对象来对元素进行排序。
  * 
  * 如果在 PriorityQueue 的排序中有多个元素具有相同的优先级,
  * 那么不能保证 dequeue 或 dequeueAll 方法返回元素的顺序。
  * 特别地,这个类不保证按先进先出的方式返回元素,尽管从类名 Queue 可以错误地推断出这种行为。
  *
  * 只有 dequeue 和 dequeueAll 方法会按照优先顺序(同时从堆中删除元素)返回元素。
  * 标准集合方法,如 drop、iterator 和 toString,将按照最方便的顺序删除或遍历堆。
  *
  * 因此,打印一个 PriorityQueue 不会显示元素的优先顺序,
  * 虽然优先级最高的元素将首先被打印出来。
  * 要按顺序打印元素,必须复制 PriorityQueue(例如使用 clone 方法),然后逐个出队:
  *
  * @example {
   {
   {
  * val pq = collection.mutable.PriorityQueue(1, 2, 5, 3, 7)
  * println(pq)                  // 元素可能不是按顺序的
  * println(pq.clone.dequeueAll) // 打印 Vector(7, 5, 3, 2, 1)
  * }}}
  *
  * @tparam A    PriorityQueue 中元素的类型
  * @param ord   隐式的 Ordering[A] 对象,用于比较元素的顺序。
  *
  * @author  Matthias Zenger
  * @since   1
  *
  * @define Coll PriorityQueue
  * @define coll priority queue
  * @define orderDependent
  * @define orderDependentFold
  * @define mayNotTerminateInf
  * @define willNotTerminateInf
  */
@SerialVersionUID(736425014438295802L)
sealed class PriorityQueue[A](implicit val ord: Ordering[A])
   extends AbstractIterable[A]
      with Iterable[A]
      with GenericOrderedTraversableTemplate[A, PriorityQueue]
      with IterableLike[A, PriorityQueue[A]]
      with Growable[A]
      with Builder[A, PriorityQueue[A]]
      with Serializable
      with scala.Cloneable
{
   
  import ord._

  @SerialVersionUID(3491656538574147683L)
  private class ResizableArrayAccess[A] extends AbstractSeq[A] with ResizableArray[A] with Serializable {
   
    def p_size0 = size0
    def p_size0_=(s: Int) = size0 = s
    def p_array = array
    def p_ensureSize(n: Int) = super.ensureSize(n)
    def p_swap(a: Int, b: Int) = super.swap(a, b)
  }

  protected[this] override 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值