当前位置:首页 > PHP教程 > php应用 > 列表

PHP优先级队列的介绍(附代码)

发布:smiling 来源: PHP粉丝网  添加日期:2020-02-07 20:38:13 浏览: 评论:0 

本篇文章给大家带来的内容是关于PHP优先级队列的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

PHP 的 SPL 库内置了 SplPriorityQueue优先级队列,并且是以Heap数据结构实现的,默认为MaxHeap模式,即priority越大越优先出队,同时可以通过重写compare方法来使用MinHeap(优先级越低越优先出队,场景貌似很少吧)。

SplPriorityQueue

堆特性

这里需要注意并理解:SplPriorityQueue是以堆数据结构来实现的,当我们出队时会拿出堆顶的元素,此时堆的特性被破坏,堆会进行相应的调整至稳定态(MaxHeap or MinHeap),即会将最后一个元素替换到堆顶,然后进行稳定态验证,不符合堆特性则继续调整,或者我们就得到了一个稳定态的堆,所以当优先级相同,出队顺序并不会按照入队顺序。

源码示例:

  1. <?php 
  2.  
  3. $splPriorityQueue = new \SplPriorityQueue(); 
  4.  
  5. // 设定返回数据的meta信息 
  6.  
  7. // \SplPriorityQueue::EXTR_DATA 默认 只返回数 
  8.  
  9. // \SplPriorityQueue::EXTR_PRIORITY 只返回优先级 
  10.  
  11. // \SplPriorityQueue::EXTR_BOTH 返回数据和优先级 
  12.  
  13. // $splPriorityQueue->setExtractFlags(\SplPriorityQueue::EXTR_DATA); 
  14.  
  15. $splPriorityQueue->insert("task1", 1); 
  16.  
  17. $splPriorityQueue->insert("task2", 1); 
  18.  
  19. $splPriorityQueue->insert("task3", 1); 
  20.  
  21. $splPriorityQueue->insert("task4", 1); 
  22.  
  23. $splPriorityQueue->insert("task5", 1); 
  24.  
  25. echo $splPriorityQueue->extract() . PHP_EOL; 
  26.  
  27. echo $splPriorityQueue->extract() . PHP_EOL; 
  28.  
  29. echo $splPriorityQueue->extract() . PHP_EOL; 
  30.  
  31. echo $splPriorityQueue->extract() . PHP_EOL; 
  32.  
  33. echo $splPriorityQueue->extract() . PHP_EOL; 
  34.  
  35. //执行结果 
  36.  
  37. task1 
  38.  
  39. task5 
  40.  
  41. task4 
  42.  
  43. task3 
  44.  
  45. task2 

可以看到,虽然 5 个任务的优先级相同,但队列并没有按照入队顺序返回数据,因为堆的特性使然:

1、入队 task1, task2, task3, task4, task5,因为优先级相同,所以堆一直处于稳定态。

2、出队,得 task1,堆先将结构调整为 task5, task2, task3, task4,已然达到了稳定态。

3、出队,得 task5,堆先将结构调整为 task4, task2, task3,已然达到了稳定态。

4、出队,得 task4,堆先将结构调整为 task3, task2,已然达到了稳定态。

5、出队,得 task3,堆先将结构调整为 task2,已然达到了稳定态。

4、出队,得 task2。

Iterator, Countable

SplPriorityQueue实现了 Iterator, Countable接口,所以我们可以foreach/count函数操作它,或者使用rewind,valid,current,next/count方法。

注意,因为是堆实现,所以rewind方法是一个no-op没有什作用的操作,因为头指针始终指向堆顶,即current始终等于top,不像List只是游走指针,出队是会删除堆元素的,extract = current + next(current出队,从堆中删除)。

  1. <?php 
  2.  
  3. $splPriorityQueue = new \SplPriorityQueue(); 
  4.   
  5. $splPriorityQueue->insert("task1", 1); 
  6.  
  7. $splPriorityQueue->insert("task2", 2); 
  8.  
  9. $splPriorityQueue->insert("task3", 1); 
  10.  
  11. $splPriorityQueue->insert("task4", 4); 
  12.  
  13. $splPriorityQueue->insert("task5", 5); 
  14.   
  15. echo "Countable: " . count($splPriorityQueue) . PHP_EOL;  
  16.  
  17. // 迭代的话会删除队列元素 current 指针始终指向 top 所以 rewind 没什么意义 
  18.  
  19. for ($splPriorityQueue->rewind(); $splPriorityQueue->valid();$splPriorityQueue->next()) {  
  20.  
  21.     var_dump($splPriorityQueue->current()); 
  22.  
  23.     var_dump($splPriorityQueue->count()); 
  24.  
  25.     $splPriorityQueue->rewind(); 
  26.  
  27.  
  28. var_dump("is empty:" . $splPriorityQueue->isEmpty()); 

Extract出队

extract 出队更为友好,即始终返回优先级最高的元素,优先级相投时会以堆调整的特性返回数据。

  1. <?php 
  2.  
  3. $splPriorityQueue = new \SplPriorityQueue(); 
  4.   
  5. // data  priority 
  6.  
  7. $splPriorityQueue->insert("task1", 1); 
  8.  
  9. $splPriorityQueue->insert("task2", 2); 
  10.  
  11. $splPriorityQueue->insert("task3", 1); 
  12.  
  13. $splPriorityQueue->insert("task4", 4); 
  14.  
  15. $splPriorityQueue->insert("task5", 5); 
  16.  
  17. echo "Countable: " . count($splPriorityQueue) . PHP_EOL; 
  18.  
  19. //phpfensi.com 
  20.  
  21. while (! $splPriorityQueue->isEmpty()) { 
  22.  
  23.     var_dump($splPriorityQueue->extract()); 
  24.  
  25.     echo $splPriorityQueue->count() . PHP_EOL; 
  26.  

自定义优先级处理方式

重写compare方法定义自己的优先级处理机制。

  1. <?php 
  2.  
  3. class CustomedSplPriorityQueue extends SplPriorityQueue 
  4.  
  5.  
  6.     public function compare($priority1$priority2): int 
  7.  
  8.     { 
  9.  
  10.         // return $priority1 - $priority2;//高优先级优先 
  11.  
  12.         return $priority2 - $priority1;//低优先级优先 
  13.  
  14.     } 
  15.  
  16.  
  17. $splPriorityQueue = new \CustomedSplPriorityQueue(); 
  18.  
  19. $splPriorityQueue->setExtractFlags(SplPriorityQueue::EXTR_BOTH); 
  20.  
  21. $splPriorityQueue->insert("task1", 1); 
  22.  
  23. $splPriorityQueue->insert("task2", 2); 
  24.  
  25. $splPriorityQueue->insert("task3", 1); 
  26.  
  27. $splPriorityQueue->insert("task4", 4); 
  28.  
  29. $splPriorityQueue->insert("task5", 5); 
  30.  
  31. echo "Countable: " . count($splPriorityQueue) . PHP_EOL; 
  32.  
  33. while (!$splPriorityQueue->isEmpty()) { 
  34.  
  35.     var_dump($splPriorityQueue->extract()); 
  36.  

Tags: PHP优先级队列

分享到: