算法笔记-PHP实现队列的操作
【队列】先进者先出,这就是典型的“队列”。
最基本的两个操作:入队enqueue(),放一个数据到队列尾部;出队dequeue(),从队列头部取一个元素。队列可以用数组或者链表实现,用数组实现的队列叫作顺序队列,用链表实现的队列叫作链式队列。
队列需要两个指针:一个是 head 指针,指向队头;一个是 tail 指针,指向队尾。
在数组实现队列的时候,会有数据搬移操作,要想解决数据搬移的问题,我们就需要像环一样的循环队列。
阻塞队列就是在队列为空的时候,从队头取数据会被阻塞,因为此时还没有数据可取,直到队列中有了数据才能返回;如果队列已经满了,那么插入数据的操作就会被阻塞,直到队列中有空闲位置后再插入数据,然后在返回。
在多线程的情况下,会有多个线程同时操作队列,这时就会存在线程安全问题。能够有效解决线程安全问题的队列就称为并发队列。
基于链表的实现方式,可以实现一个支持无限排队的无界队列(unbounded queue),但是可能会导致过多的请求排队等待,请求处理的响应时间过长。所以,针对响应时间比较敏感的系统,基于链表实现的无限排队的线程池是不合适的。
而基于数组实现的有界队列(bounded queue),队列的大小有限,所以线程池中排队的请求超过队列大小时,接下来的请求就会被拒绝,这种方式对响应时间敏感的系统来说,就相对更加合理。不过,设置一个合理的队列大小,也是非常有讲究的。队列太大导致等待的请求太多,队列太小会导致无法充分利用系统资源、发挥最大性能。
实际上,对于大部分资源有限的场景,当没有空闲资源时,基本上都可以通过“队列”这种数据结构来实现请求排队。
<?php /** * 队列 链表实现 * * Class QueueOnLinkedList */ class QueueOnLinkedList { /** * 队列头节点 * * @var SingleLinkedListNode */ public $head; /** * 队列尾节点 * * @var null */ public $tail; /** * 队列长度 * * @var int */ public $length; /** * QueueOnLinkedList constructor. */ public function __construct() { $this->head = new SingleLinkedListNode(); $this->tail = $this->head; $this->length = 0; } /** * 入队 * * @param $data */ public function enqueue($data) { $newNode = new SingleLinkedListNode(); $newNode->data = $data; $this->tail->next = $newNode; $this->tail = $newNode; $this->length++; } /** * 出队 * * @return SingleLinkedListNode|bool|null */ public function dequeue() { if (0 == $this->length) { return false; } $node = $this->head->next; $this->head->next = $this->head->next->next; $this->length--; return $node; } /** * 获取队列长度 * * @return int */ public function getLength() { return $this->length; } /** * 打印队列 */ public function printSelf() { if (0 == $this->length) { echo 'empty queue' . PHP_EOL; return; } echo 'head.next -> '; $curNode = $this->head; while ($curNode->next) { echo $curNode->next->data . ' -> '; $curNode = $curNode->next; } echo 'NULL' . PHP_EOL; } }
调用:
<?php $queue = new QueueOnLinkedList(); $queue->enqueue(1); $queue->enqueue(2); $queue->enqueue(3); $queue->enqueue(4); $queue->enqueue(5); $queue->printSelf(); var_dump($queue->getLength()); $queue->dequeue(); $queue->printSelf(); $queue->dequeue(); $queue->dequeue(); $queue->dequeue(); $queue->printSelf(); $queue->dequeue(); $queue->printSelf();
运行: