PHP 的 SPL 庫內置了 SplPriorityQueue優先級隊列,并且是以Heap數據結構實現的,默認為MaxHeap模式,即priority越大越優先出隊,同時可以通過重寫compare方法來使用MinHeap(優先級越低越優先出隊,場景貌似很少吧)。
SplPriorityQueue
堆特性
這里需要注意并理解:SplPriorityQueue是以堆數據結構來實現的,當我們出隊時會拿出堆頂的元素,此時堆的特性被破壞,堆會進行相應的調整至穩定態(MaxHeap or MinHeap),即會將最后一個元素替換到堆頂,然后進行穩定態驗證,不符合堆特性則繼續調整,或者我們就得到了一個穩定態的堆,所以當優先級相同,出隊順序并不會按照入隊順序。
源碼示例:
?php$splPriorityQueue = new /SplPriorityQueue();// 設定返回數據的meta信息// /SplPriorityQueue::EXTR_DATA 默認 只返回數// /SplPriorityQueue::EXTR_PRIORITY 只返回優先級// /SplPriorityQueue::EXTR_BOTH 返回數據和優先級// $splPriorityQueue- setExtractFlags(/SplPriorityQueue::EXTR_DATA);$splPriorityQueue- insert( task1 , 1);$splPriorityQueue- insert( task2 , 1);$splPriorityQueue- insert( task3 , 1);$splPriorityQueue- insert( task4 , 1);$splPriorityQueue- insert( task5 , 1);echo $splPriorityQueue- extract() . PHP_EOL;echo $splPriorityQueue- extract() . PHP_EOL;echo $splPriorityQueue- extract() . PHP_EOL;echo $splPriorityQueue- extract() . PHP_EOL;echo $splPriorityQueue- extract() . PHP_EOL;//執行結果task1task5task4task3task2
可以看到,雖然 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,html' target='_blank'>current,next/count方法。
注意,因為是堆實現,所以rewind方法是一個no-op沒有什作用的操作,因為頭指針始終指向堆頂,即current始終等于top,不像List只是游走指針,出隊是會刪除堆元素的,extract = current + next(current出隊,從堆中刪除)。
?php$splPriorityQueue = new /SplPriorityQueue();$splPriorityQueue- insert( task1 , 1);$splPriorityQueue- insert( task2 , 2);$splPriorityQueue- insert( task3 , 1);$splPriorityQueue- insert( task4 , 4);$splPriorityQueue- insert( task5 , 5);echo Countable: . count($splPriorityQueue) . PHP_EOL;// 迭代的話會刪除隊列元素 current 指針始終指向 top 所以 rewind 沒什么意義for ($splPriorityQueue- rewind(); $splPriorityQueue- valid();$splPriorityQueue- next()) { var_dump($splPriorityQueue- current()); var_dump($splPriorityQueue- count()); $splPriorityQueue- rewind();var_dump( is empty: . $splPriorityQueue- isEmpty());
Extract出隊
extract 出隊更為友好,即始終返回優先級最高的元素,優先級相投時會以堆調整的特性返回數據。
?php$splPriorityQueue = new /SplPriorityQueue();// data priority$splPriorityQueue- insert( task1 , 1);$splPriorityQueue- insert( task2 , 2);$splPriorityQueue- insert( task3 , 1);$splPriorityQueue- insert( task4 , 4);$splPriorityQueue- insert( task5 , 5);echo Countable: . count($splPriorityQueue) . PHP_EOL;while (! $splPriorityQueue- isEmpty()) { var_dump($splPriorityQueue- extract()); echo $splPriorityQueue- count() . PHP_EOL;}
自定義優先級處理方式
重寫compare方法定義自己的優先級處理機制。
?phpclass CustomedSplPriorityQueue extends SplPriorityQueue public function compare($priority1, $priority2): int // return $priority1 - $priority2;//高優先級優先 return $priority2 - $priority1;//低優先級優先$splPriorityQueue = new /CustomedSplPriorityQueue();$splPriorityQueue- setExtractFlags(SplPriorityQueue::EXTR_BOTH);$splPriorityQueue- insert( task1 , 1);$splPriorityQueue- insert( task2 , 2);$splPriorityQueue- insert( task3 , 1);$splPriorityQueue- insert( task4 , 4);$splPriorityQueue- insert( task5 , 5);echo Countable: . count($splPriorityQueue) . PHP_EOL;while (!$splPriorityQueue- isEmpty()) { var_dump($splPriorityQueue- extract());}
本篇文章到這里就已經全部結束了,更多其他精彩內容可以關注PHP 的PHP視頻教程欄目!
以上就是PHP優先級隊列的介紹(附代碼)的詳細內容,PHP教程
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答