本文目录导读:

在PHP中,实现优先级队列有多种方法,以下是几种常见的实现方式:
使用 SplPriorityQueue(推荐)
PHP 内置的 SplPriorityQueue 是最简单的实现方式:
<?php
class PriorityQueueDemo {
private $queue;
public function __construct() {
$this->queue = new SplPriorityQueue();
}
public function enqueue($value, $priority) {
// 注意:SplPriorityQueue 默认是最大优先级优先
$this->queue->insert($value, $priority);
}
public function dequeue() {
if (!$this->queue->isEmpty()) {
return $this->queue->extract();
}
return null;
}
public function processAll() {
while (!$this->queue->isEmpty()) {
echo $this->queue->extract() . "\n";
}
}
}
// 使用示例
$queue = new PriorityQueueDemo();
$queue->enqueue("普通任务", 1);
$queue->enqueue("紧急任务", 100);
$queue->enqueue("次要任务", 0);
$queue->enqueue("重要任务", 50);
$queue->processAll();
// 输出: 紧急任务 重要任务 普通任务 次要任务
自定义优先级队列实现
如果需要更多控制,可以实现自己的优先级队列:
<?php
class CustomPriorityQueue {
private $heap = [];
public function enqueue($element, $priority) {
$this->heap[] = [
'element' => $element,
'priority' => $priority
];
$this->siftUp(count($this->heap) - 1);
}
public function dequeue() {
if (empty($this->heap)) {
return null;
}
$root = $this->heap[0];
$last = array_pop($this->heap);
if (!empty($this->heap)) {
$this->heap[0] = $last;
$this->siftDown(0);
}
return $root['element'];
}
private function siftUp($index) {
while ($index > 0) {
$parentIndex = intval(($index - 1) / 2);
if ($this->heap[$index]['priority'] <= $this->heap[$parentIndex]['priority']) {
break;
}
// 交换
$temp = $this->heap[$index];
$this->heap[$index] = $this->heap[$parentIndex];
$this->heap[$parentIndex] = $temp;
$index = $parentIndex;
}
}
private function siftDown($index) {
$size = count($this->heap);
while (true) {
$largest = $index;
$left = 2 * $index + 1;
$right = 2 * $index + 2;
if ($left < $size && $this->heap[$left]['priority'] > $this->heap[$largest]['priority']) {
$largest = $left;
}
if ($right < $size && $this->heap[$right]['priority'] > $this->heap[$largest]['priority']) {
$largest = $right;
}
if ($largest === $index) {
break;
}
// 交换
$temp = $this->heap[$index];
$this->heap[$index] = $this->heap[$largest];
$this->heap[$largest] = $temp;
$index = $largest;
}
}
public function isEmpty() {
return empty($this->heap);
}
public function count() {
return count($this->heap);
}
}
使用数组实现简单优先级队列
对于简单场景,可以使用数组排序:
<?php
class SimplePriorityQueue {
private $items = [];
public function enqueue($value, $priority) {
$this->items[] = [
'value' => $value,
'priority' => $priority
];
// 按优先级降序排序
usort($this->items, function($a, $b) {
return $b['priority'] <=> $a['priority'];
});
}
public function dequeue() {
if (empty($this->items)) {
return null;
}
$item = array_shift($this->items);
return $item['value'];
}
public function peek() {
if (empty($this->items)) {
return null;
}
return $this->items[0]['value'];
}
}
任务调度器示例
一个实用的优先级队列应用示例:
<?php
class TaskScheduler {
private $queue;
public function __construct() {
$this->queue = new SplPriorityQueue();
}
public function addTask(string $taskName, callable $task, int $priority) {
$this->queue->insert([
'name' => $taskName,
'task' => $task
], $priority);
}
public function executeAll() {
$this->queue->setExtractFlags(SplPriorityQueue::EXTR_DATA);
while (!$this->queue->isEmpty()) {
$taskData = $this->queue->extract();
echo "执行任务: {$taskData['name']}\n";
// 执行任务
call_user_func($taskData['task']);
}
}
}
// 使用示例
$scheduler = new TaskScheduler();
// 添加不同优先级的任务
$scheduler->addTask("发送邮件通知", function() {
echo " 发送邮件完成\n";
}, 50);
$scheduler->addTask("处理支付", function() {
echo " 处理支付完成\n";
}, 100); // 最高优先级
$scheduler->addTask("更新日志", function() {
echo " 更新日志完成\n";
}, 10);
$scheduler->executeAll();
带权重的优先级队列
<?php
class WeightedPriorityQueue {
private $queue;
private $counter = 0;
public function __construct() {
$this->queue = new SplPriorityQueue();
}
public function enqueue($value, $basePriority, $weight = 1.0) {
// 计算最终优先级
$finalPriority = $basePriority * $weight;
// 使用 counter 确保相同优先级的元素按插入顺序处理
$this->queue->insert($value, [$finalPriority, -$this->counter]);
$this->counter++;
}
public function dequeue() {
if (!$this->queue->isEmpty()) {
return $this->queue->extract();
}
return null;
}
}
性能对比
| 方法 | 入队复杂度 | 出队复杂度 | 特点 |
|---|---|---|---|
| SplPriorityQueue | O(log n) | O(log n) | 内置实现,性能好 |
| 自定义堆实现 | O(log n) | O(log n) | 灵活可定制 |
| 数组排序法 | O(n log n) | O(n) | 简单但效率低 |
| 有序列表 | O(n) | O(1) | 插入慢,取出快 |
最佳实践建议
- 优先使用 SplPriorityQueue:除非有特殊需求,否则使用 PHP 内置的实现
- 注意内存管理:处理大量元素时注意内存使用
- 考虑并发访问:在多线程环境中需要考虑线程安全
- 错误处理:处理空队列的情况
选择合适的实现方式取决于你的具体需求,如性能要求、灵活性要求和代码复杂性等。