/** * Perform a depth-first traversal on the provided graph. * * @param Digraph $graph * The graph on which to perform the depth-first search. * @param DepthFirstVisitorInterface $visitor * The visitor object to use during the traversal. * @param object|\SplDoublyLinkedList $start * A vertex, or vertices, to use as start points for the traversal. There * are a few sub-behaviors here: * - If an SplDoublyLinkedList, SplQueue, or SplStack is provided, the * traversal will deque and visit vertices contained therein. * - If a single vertex object is provided, it will be the sole * originating point for the traversal. * - If no value is provided, DepthFirst::find_sources() is called to * search the graph for source vertices. These are place into an * SplQueue in the order in which they are discovered, and traversal * is then run over that queue in the same manner as if calling code * had provided a queue directly. This method *guarantees* that all * vertices in the graph will be visited. * * @throws RuntimeException * Thrown if an invalid $start parameter is provided. */ public static function traverse(Digraph $graph, DepthFirstVisitorInterface $visitor, $start = NULL) { if ($start === NULL) { $queue = self::find_sources($graph, $visitor); } else { if ($start instanceof \SplDoublyLinkedList) { $queue = $start; } else { if (is_object($start)) { $queue = new \SplDoublyLinkedList(); $queue->push($start); } } } if ($queue->isEmpty()) { throw new RuntimeException('No start vertex or vertices were provided, and no source vertices could be found in the provided graph.', E_WARNING); } $visiting = new \SplObjectStorage(); $visited = new \SplObjectStorage(); $visitor->beginTraversal(); $visit = function ($vertex) use($graph, $visitor, &$visit, $visiting, $visited) { if ($visiting->contains($vertex)) { $visitor->onBackEdge($vertex, $visit); } else { if (!$visited->contains($vertex)) { $visiting->attach($vertex); $visitor->onStartVertex($vertex, $visit); foreach ($graph->successorsOf($vertex) as $head) { $visitor->onExamineEdge($vertex, $head, $visit); $visit($head); } $visitor->onFinishVertex($vertex, $visit); $visiting->detach($vertex); $visited->attach($vertex); } } }; // TODO experiment with adding a generator-producing visitor method that yields the queue here while (!$queue->isEmpty()) { $vertex = $queue->shift(); $visit($vertex); } $visitor->endTraversal(); }
/** * Perform a depth-first traversal on the provided graph. * * @param DirectedGraph $graph * The graph on which to perform the depth-first search. * @param DepthFirstVisitorInterface $visitor * The visitor object to use during the traversal. * @param object|\SplDoublyLinkedList $start * A vertex, or vertices, to use as start points for the traversal. There * are a few sub-behaviors here: * - If an SplDoublyLinkedList, SplQueue, or SplStack is provided, the * traversal will deque and visit vertices contained therein. * - If a single vertex object is provided, it will be the sole * originating point for the traversal. * - If no value is provided, DepthFirst::find_sources() is called to * search the graph for source vertices. These are place into an * SplQueue in the order in which they are discovered, and traversal * is then run over that queue in the same manner as if calling code * had provided a queue directly. This method *guarantees* that all * vertices in the graph will be visited. * * @throws RuntimeException * Thrown if an invalid $start parameter is provided. */ public static function traverse(DirectedGraph $graph, DepthFirstVisitorInterface $visitor, $start = NULL) { if ($start === NULL) { $queue = self::find_sources($graph, $visitor); } else { if ($start instanceof \SplDoublyLinkedList) { $queue = $start; } else { if (is_object($start)) { $queue = new \SplDoublyLinkedList(); $queue->push($start); } } } if ($queue->isEmpty()) { throw new RuntimeException('No start vertex or vertices were provided, and no source vertices could be found in the provided graph.', E_WARNING); } $visiting = new \SplObjectStorage(); $visited = new \SplObjectStorage(); $visitor->beginTraversal(); $visit = function ($vertex) use($graph, $visitor, &$visit, $visiting, $visited) { if ($visiting->contains($vertex)) { $visitor->onBackEdge($vertex, $visit); } else { if (!$visited->contains($vertex)) { $visiting->attach($vertex); $visitor->onStartVertex($vertex, $visit); $graph->eachAdjacent($vertex, function ($to) use($vertex, &$visit, $visitor) { $visitor->onExamineEdge($vertex, $to, $visit); $visit($to); }); $visitor->onFinishVertex($vertex, $visit); $visiting->detach($vertex); $visited->attach($vertex); } } }; while (!$queue->isEmpty()) { $vertex = $queue->shift(); $visit($vertex); } $visitor->endTraversal(); }
// offsetSet($index, $newValue) // 设置参数索引的节点值, $index必须在链表的键范围中。 // 当一个节点用offsetUnset删掉时时,并不能用offsetSet重新给已删掉的节点设置值,只能对当前可见的节点的值进行修改 $list->offsetSet(3, 'value6'); // offsetUnset($index) // 删除参数索引的节点 $list->offsetUnset(3); // add($index, $value); // 对指定的索引新增一个新值。 当一个节点用offsetUnset时,并没有直接删除,该节点还仍然会保存在内存中。用add可以重新给该节点设置值 $list->add(3, 'first'); // unshift($value) // 在链表的开始节点插入value作为新的开始节点 $list->unshift('second'); // shift() // 将链表的第一个移除 $list->shift(); // setIteratorMode(int $mode) // 设置链表的模式。等价于下面的情况: // IT_MODE_LIFO: 栈模式,先进后出;IT_MODE_FIFO:队列模式,先进先出 // IT_MODE_DELETE; IT_MODE_KEEP $list->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO); // getIteratorMode() // 获得链表的模式 $list->getIteratorMode(); echo "example: \n"; echo "FIFO (First In First Out): \n"; $list->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO); for ($list->rewind(); $list->valid(); $list->next()) { echo $list->current() . "\n"; } echo "LIFO (First In First Out): \n";
<?php $dll = new SplDoublyLinkedList(); // errors try { $dll->pop(); } catch (RuntimeException $e) { echo "Exception: " . $e->getMessage() . "\n"; } try { $dll->shift(); } catch (RuntimeException $e) { echo "Exception: " . $e->getMessage() . "\n"; } // data consistency $a = 2; $dll->push($a); echo $dll->pop() . "\n"; $a = 2; $dll->unshift($a); echo $dll->shift() . "\n"; // peakable $dll->push(1); $dll->push(2); echo $dll->top() . "\n"; echo $dll->bottom() . "\n"; $dll->pop(); $dll->pop(); // countable $dll->push(NULL); $dll->push(NULL);
<?php $ll = new SplDoublyLinkedList(); $ll->push(1); $ll->push(2); var_dump($ll->shift(1));
/** @return the first element of the queue. * @note dequeue is an alias of push() * @see splDoublyLinkedList::push() */ public function dequeue() { return parent::shift(); }
<?php $dll = new SplDoublyLinkedList(); $dll->unshift('foo'); $dll->unshift('bar'); echo $dll->shift(), PHP_EOL; $dll->rewind(); echo $dll->current(), PHP_EOL; $dll->prev(); echo $dll->current(), PHP_EOL;
/** * Shifts a `Token` from the beginning of the list. * * @return Token The shifted token. * @link http://www.php.net/manual/en/spldoublylinkedlist.shift.php */ public function shift() { return $this->tokens->shift(); }