当前位置: 首页 > 后端技术 > PHP

PHP优先级队列:SplPriorityQueue

时间:2023-03-30 03:20:25 PHP

PHP的SPL库内置了一个SplPriorityQueue优先级队列,它是用Heap数据结构实现的。默认是MaxHeap模式,即优先级越大越优先出队。同时可以重写compare方法为UseMinHeap(优先级越低越优先出队,貌似很少有这种场景)。这里需要注意和理解SplPriorityQueue的堆特性:SplPriorityQueue是用堆数据结构实现的。当我们离开队列时,我们会取出堆顶元素。此时堆的特性被破坏,堆会相应调整到稳定状态(MaxHeap或MinHeap),即最后一个元素会被替换到堆顶,然后稳定状态将进行验证。如果不符合堆特性,继续调整,否则我们会得到一个稳定的堆,所以当优先级相同时,出队顺序不是入队顺序。源码示例: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;发现虽然5个task的优先级相同,但是queue返回数据的顺序并不是enqueue的顺序,因为heap的特点:1.enqueuetask1,task2,task3,task4,task5,因为优先级是相同,因此堆始终处于稳定状态。2.出队,拿到task1,调整堆结构到task5,task2,task3,task4,已经达到稳定状态。3.出队,拿到task5。堆首先调整结构为task4、task2、task3,已经达到稳定状态。4.出队,拿到task4。堆首先调整结构到task3和task2,已经达到稳定状态。5.出队,拿到task3。heap首先对task2进行结构调整,task2已经达到稳定状态。4.出队,得到task2。Iterator,CountableSplPriorityQueue实现了Iterator,Countable接口,所以我们可以用foreach/count函数对其进行操作,或者使用rewind,valid,current,next/count方法。注意,因为是堆实现,所以rewind方法是没有效果的no-op操作,因为head指针永远指向堆顶,即current永远等于top,不像List,只是一个游走指针,出队时会删除堆元素是的,extract=current+next(current出队并从堆中删除)。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;//队列元素当前将迭代时被删除指针总是指向top所以rewind没有意义->count());$splPriorityQueue->rewind();}var_dump("为空:".$splPriorityQueue->isEmpty());extractdequeueextractdequeue比较友好,即总是返回优先级最高的元素,当优先级相同时,会返回具有堆调整特性的数据。insert("task1",1);$splPriorityQueue->insert("task2",2);$splPriorityQueue->insert("task3",1);$splPriorityQueue->insert("task4",4);$splPriorityQueue->insert("task5",5);回声“可数:”。计数($splPriorityQueue)。PHP_EOL;while(!$splPriorityQueue->isEmpty()){var_dump($splPriorityQueue->extract());回显$splPriorityQueue->count()。PHP_EOL;}自定义优先级处理覆盖比较方法来定义自己的优先级处理机制。setExtractFlags(SplPriorityQueue::EXTR_BOTH);$splPriorityQueue->insert("task1",1);$splPriorityQueue->insert("task2",2);$splPriorityQueue->插入(“任务3”,1);$splPriorityQueue->插入(“任务4”,4);$splPriorityQueue->插入(“任务5”,5);echo"可数:".计数($splPriorityQueue)。PHP_EOL;while(!$splPriorityQueue->isEmpty()){var_dump($splPriorityQueue->extract());}