基本上SplPriorityQueue
类是使用max heap
algoritm的堆。
我不明白为什么文档应该是prioritized queue
,因为queue
是 FIFO 集合(先进先出) - 但是因为SplPriorityQueue
它取决于priority variable
的比较函数,为什么它是一个队列?
为什么课程不仅仅是SplPriorityCollection
?!
- > SplPriorityQueue documentation
受 Mark Baker的启发评论我测试了比较功能的行为,当所有项目的优先级相同时,结果表明,具有相同优先级的集合不是 FIFO < /强>
$objPQ = new SplPriorityQueue();
$objPQ->insert('A', 1);
$objPQ->insert('B', 1);
$objPQ->insert('C', 1);
$objPQ->insert('D', 1);
$objPQ->insert('E', 1);
$objPQ->insert('F', 1);
$objPQ->insert('G', 1);
foreach($objPQ as $val) {
echo $val . "\n";
}
输出:
A G F E D C B
答案 0 :(得分:5)
基本上
SplPriorityQueue
类是使用max heap
algoritm [sic]的堆。
使用堆的事实是实现细节,使用堆不是必需的。优先级队列数据结构也不是PHP独有的(不是有人说它是!)。希望维基百科的以下简短引用有助于:
虽然优先级队列通常使用堆来实现,但它们在概念上与堆不同。优先级队列是一个抽象概念,如“列表”或“地图”;就像列表可以用链表或数组实现一样,优先级队列可以用堆或各种其他方法实现,例如无序数组。
同一来源也有以下说法:
如果两个元素具有相同的优先级,则根据队列中的顺序提供它们
这与SplPriorityQueue的作者在PHP错误报告([Won't Fix] Bug #53710 Data registered with equal priority not returned in expected order)中的评论相反,后者描述了具有相同优先级值的迭代(错误)行为。
没有这样的保证。你唯一的保证 SplPriorityQueue是你不会出现乱序的元素。元素与 以任意顺序提取相同的优先级,其余的是实现 依赖
上述错误报告的作者继续撰写了一篇博客文章Taming SplPriorityQueue,该帖子使用以下技术实施可预测的队列顺序:
namespace Foo;
class SplPriorityQueue extends \SplPriorityQueue
{
protected $queueOrder = PHP_INT_MAX;
public function insert($datum, $priority)
{
if (is_int($priority)) {
$priority = array($priority, $this->queueOrder--);
}
parent::insert($datum, $priority);
}
}
答案 1 :(得分:1)
SPLPriorityQueue看起来更像是一个堆而不是一个队列,应该用它作为队列的FIFO方面是不适用的
但是,可以通过修改插入来调整比较函数中使用的值
来恢复FIFOclass PQtest extends SplPriorityQueue
{
protected $serial = PHP_INT_MAX;
public function insert($value, $priority) {
parent::insert($value, array($priority, $this->serial--));
}
public function compare($priority1, $priority2)
{
if ($priority1 === $priority2) return 0;
return $priority1 < $priority2 ? -1 : 1;
}
}
$objPQ = new PQtest();
$objPQ->insert('A',1);
$objPQ->insert('B',1);
$objPQ->insert('C',1);
$objPQ->insert('D',1);
$objPQ->insert('E',1);
$objPQ->insert('F',1);
echo "COUNT->".$objPQ->count().PHP_EOL;
//mode of extraction
$objPQ->setExtractFlags(PQtest::EXTR_BOTH);
//Go to TOP
$objPQ->top();
while($objPQ->valid()){
print_r($objPQ->current());
echo PHP_EOL;
$objPQ->next();
}