Подтвердить что ты не робот

Изменение приоритета элементов в очереди приоритетов

Используя Scala 2.9 для реализации своего рода алгоритма Дейкстры (псевдокода)

val queue = new PriorityQueue
queue.insert(...)
while (!queue.isEmpty) {
  val u = queue.extractMin
  queue.foreach { v =>
    if (condition(u, v))
      queue.decreaseKey(v, newPriority)
  }
}

Я хочу изменить приоритет элемента в Scala collection.mutable.PriorityQueue.

Поэтому попытался

  • удалить элемент
  • изменить приоритет
  • вставьте в очередь.

Но я не могу найти метод для обновления приоритета или удаления определенного элемента (не обязательно элемент головы), как java.util.PriorityQueue#remove(Object), как показано в Удаление элемента из очереди приоритетов.

  • Как выполнить эту задачу с помощью scala.collection.mutable.PriorityQueue или мне нужно вместо этого использовать java.util.PriorityQueue?

  • Кто-нибудь знает, есть ли недостаток такого метода по дизайну, и было бы рекомендовано для восстановления очереди после изменения приоритета некоторых элементов (возможно, взгляните на обсуждение очереди с приоритетами динамических элементов)

4b9b3361

Ответ 1

Определение класса case для типа PriorityQueue для использования с var для приоритета позволяет вам найти его и изменить приоритет. При этом PriorityQueue имеет это новое значение. Чтобы правильно упорядочить заказ, мне пришлось клонировать его, который переупорядочивает/заставляет упорядочивать. Возможно, лучший способ сделать это без клонирования.

case class Elem(var priority: Int, i: Int)

def MyOrdering = new Ordering[Elem] {
  def compare(a : Elem, b : Elem) = a.priority.compare(b.priority)
}

val pq = new scala.collection.mutable.PriorityQueue[Elem]()(MyOrdering)  ++ List(Elem(1,1), Elem(0,0), Elem(2,2))

pq.find(x => x.priority == 0) match {
  case Some(elem: Elem) => elem.priority = 3
  case None => println("Not found")
}

val pq2 = pq.clone
println(pq2)
println(pq2.dequeue)
println(pq2.dequeue)
println(pq2.dequeue)



:load SO.scala
Loading SO.scala...
defined class Elem
PileOrdering: java.lang.Object with Ordering[Elem]
pq: scala.collection.mutable.PriorityQueue[Elem] = PriorityQueue(Elem(2,2), Elem(0,0), Elem(1,1))
pq2: scala.collection.mutable.PriorityQueue[Elem] = PriorityQueue(Elem(3,0), Elem(2,2), Elem(1,1))
PriorityQueue(Elem(3,0), Elem(2,2), Elem(1,1))
Elem(3,0)
Elem(2,2)
Elem(1,1)

Ответ 2

Очереди приоритетов обычно реализуются с помощью кучи. Двоичные кучи обычно реализуются с использованием массивов, и если элемент, который вы хотите удалить, не находится на пути между корнем кучи и его последним элементом в упорядочении массива, то нет очевидного способа его удалить. Я предполагаю, что именно поэтому Scala не предлагает удаление произвольных элементов. Однако, если вы реализуете свою собственную кучу, достаточно просто реализовать уменьшающий ключ для двоичной (min-) кучи: вы просто сравниваете новый приоритет для node N с его родительским приоритетом и при необходимости обмениваете два. Повторяйте это до тех пор, пока N не будет наверху или N родительский имеет более низкий приоритет, чем N.

Ответ 3

У меня нет опыта работы с Scala, но проблема, которую я вижу, заключается в том, что для Dijkstra недостаточно простой очереди очередности, так как вам нужно знать, где определенная вершина хранится в очереди, прежде чем вы сможете сделать сокращение, ключ. Другими словами, для отображения вершинных идентификаторов в индексы в куче в ожидаемое постоянное время требуется словарь (хеш-таблица). Затем вы получаете общий O (log n) для клавиши уменьшения. Мне кажется маловероятным, что такую ​​функциональность можно найти в стандартной библиотеке. Написание подходящего класса с нуля должно быть легко.

Код в конце эта лекция объясняет идею (но в python.. извините).

Ответ 4

Не пользователь Scala, но до сих пор я никогда не видел встроенную/предварительно созданную реализацию кучи, которая позволяет использовать Key Decrease, потому что Key Decrease эффективен только в том случае, если вы можете предоставить (местоположение) элемент DK'd.

Самый простой способ получить операцию DK - реализовать кучу самостоятельно. Мой метод обычно заключается в том, чтобы отдельные элементы были разделены (в неорганизованном массиве/векторе/связанном списке) и для создания кучи указателей-элементов (или массивов-индексов). Затем, учитывая кучу node, вы можете найти элемент, обратившись к нему в массиве (разыменование или индексный поиск). Для поддержки DK и/или случайного удаления вы можете добавить дополнительную переменную к элементу, который указывает на кучу node (или хранит индекс, если массив на основе массива). Это позволяет вам иметь доступ O (1) в любом направлении.

Если ваша готовая куча поставляется с операцией DK, которая принимает указатель на node, тогда вы можете просто создать кучу самодельных объектов node, которые просто переносят указатель в класс, чтобы вы может предоставить операторов сравнения (необходимых для создания кучи).