public function __construct() { $this->queue = new \SplPriorityQueue(); $this->timer = Loop\periodic(1, function () { $time = time(); while (!$this->queue->isEmpty()) { $key = $this->queue->top(); if (isset($this->expire[$key])) { if ($time <= $this->expire[$key]) { break; } unset($this->data[$key], $this->expire[$key], $this->ttl[$key]); } $this->queue->extract(); } if ($this->queue->isEmpty()) { $this->timer->stop(); } }); $this->timer->stop(); $this->timer->unreference(); }
/** * @see QueueInterface::pop() */ public function pop() { if (!$this->innerQueue->isEmpty()) { $eta = $this->innerQueue->top()->getEta(); if (!$eta || $eta->getTimestamp() <= time()) { return $this->innerQueue->extract(); } } return false; }
/** * {@inheritdoc} */ public function pop() { if (!$this->queue->isEmpty()) { $this->queue->setExtractFlags(\SplPriorityQueue::EXTR_PRIORITY); $priority = $this->queue->top(); if (time() + $priority[0] >= 0) { $this->queue->setExtractFlags(\SplPriorityQueue::EXTR_DATA); return $this->queue->extract(); } } throw new NoItemAvailableException($this); }
/** * {@inheritdoc} */ public function pop() { if ($this->queue->isEmpty()) { return; } $this->queue->setExtractFlags(\SplPriorityQueue::EXTR_PRIORITY); $priority = $this->queue->top(); if (time() + $priority[0] >= 0) { $this->queue->setExtractFlags(\SplPriorityQueue::EXTR_DATA); return $this->queue->extract(); } }
/** * 主循环 * @see Events\EventInterface::loop() */ public function loop() { $e = null; while (1) { // 如果有信号,尝试执行信号处理函数 pcntl_signal_dispatch(); $read = $this->_readFds; $write = $this->_writeFds; // 等待可读或者可写事件 @stream_select($read, $write, $e, 0, $this->_selectTimeout); // 尝试执行定时任务 if (!$this->_scheduler->isEmpty()) { $this->tick(); } // 这些描述符可读,执行对应描述符的读回调函数 if ($read) { foreach ($read as $fd) { $fd_key = (int) $fd; if (isset($this->_allEvents[$fd_key][self::EV_READ])) { call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], array($this->_allEvents[$fd_key][self::EV_READ][1])); } } } // 这些描述符可写,执行对应描述符的写回调函数 if ($write) { foreach ($write as $fd) { $fd_key = (int) $fd; if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], array($this->_allEvents[$fd_key][self::EV_WRITE][1])); } } } } }
/** * Executes any pending timers. Returns the number of timers executed. * * @return int * * @internal */ public function tick() : int { $count = 0; $time = microtime(true); while (!$this->queue->isEmpty()) { list($timer, $timeout) = $this->queue->top(); if (!$this->timers->contains($timer) || $timeout !== $this->timers[$timer]) { $this->queue->extract(); // Timer was removed from queue. continue; } if ($this->timers[$timer] > $time) { // Timer at top of queue has not expired. return $count; } // Remove and execute timer. Replace timer if persistent. $this->queue->extract(); if ($timer->isPeriodic()) { $timeout = $time + $timer->getInterval(); $this->queue->insert([$timer, $timeout], -$timeout); $this->timers[$timer] = $timeout; } else { $this->timers->detach($timer); } // Execute the timer. $timer->call(); ++$count; } return $count; }
/** * @see Events\EventInterface::loop() */ public function loop() { $e = null; while (1) { // Calls signal handlers for pending signals pcntl_signal_dispatch(); $read = $this->_readFds; $write = $this->_writeFds; // Waiting read/write/signal/timeout events. $ret = @stream_select($read, $write, $e, 0, $this->_selectTimeout); if (!$this->_scheduler->isEmpty()) { $this->tick(); } if (!$ret) { continue; } foreach ($read as $fd) { $fd_key = (int) $fd; if (isset($this->_allEvents[$fd_key][self::EV_READ])) { call_user_func_array($this->_allEvents[$fd_key][self::EV_READ][0], array($this->_allEvents[$fd_key][self::EV_READ][1])); } } foreach ($write as $fd) { $fd_key = (int) $fd; if (isset($this->_allEvents[$fd_key][self::EV_WRITE])) { call_user_func_array($this->_allEvents[$fd_key][self::EV_WRITE][0], array($this->_allEvents[$fd_key][self::EV_WRITE][1])); } } } }
/** * Get the number of microseconds until the next timer watcher is due. * * @return int or null when no timers are pending. */ protected function nextTimeout() { $time = \microtime(true); while (!$this->scheduler->isEmpty()) { list($watcher, $scheduled) = $this->scheduler->top(); if ($watcher->enabled && $watcher->scheduled === $scheduled) { return (int) \max(0, ($watcher->due - $time) * 1000000); } } }
/** * Поиск самого дешёвого пути между двумя локациями * Для поиска используется алгоритм Дейкстры * * @see http://www.sitepoint.com/data-structures-4/ * * @param array $data Массив с локациями и ценой проезда между ними [][src, dst, cost] * @param string $source Название исходного пункта * @param string $target Название конечного пункта * * @return SplStack */ function find_path(array $data, $source, $target) { $graph = build_graph($data); // массив лучших цен кратчайшего пути для каждой локации $best_cost = []; // массив предыдущих локаций для каждой локации $prev_loc = array(); // очередь из необработанных локаций $queue = new SplPriorityQueue(); foreach ($graph as $src => $dst) { $best_cost[$src] = INF; // изначальные значения цен бесконечны $prev_loc[$src] = null; // предыдущие локации неизвестны foreach ($dst as $name => $cost) { // используем цену как приоритет в очереди $queue->insert($name, $cost); } } // цена поездки в исходный пункт = 0 $best_cost[$source] = 0; while (!$queue->isEmpty()) { // получаем минимальную цену $u = $queue->extract(); if (empty($graph[$u])) { continue; } // обрабатываем доступные маршруты для локации foreach ($graph[$u] as $v => $cost) { // альтернативная цена для маршрута $alt = $best_cost[$u] + $cost; if ($alt < $best_cost[$v]) { // обновляем минимальную цену для локации $best_cost[$v] = $alt; // добавляем локацию в массив предыдущих локаций $prev_loc[$v] = $u; } } } // ищем дешёвый путь и складываем его в стек $stack = new SplStack(); $u = $target; $final_cost = 0; // проходим в обратном порядке от пункта назначения к исходному пункту while (isset($prev_loc[$u]) && $prev_loc[$u]) { $stack->push($u); $final_cost += $graph[$u][$prev_loc[$u]]; $u = $prev_loc[$u]; } $stack->push($source); return [$stack, $final_cost]; }
/** * {@inheritdoc} */ public final function compileRoutes(RouteCompiler $compiler, RoutingContext $context) : array { $parsed = new \SplPriorityQueue(); foreach ($this->routes as $route) { foreach ($route->compile($compiler) as list($priority, $depth, $route, $regex, $mapping)) { $parsed->insert(\array_merge([$regex, $depth, $priority, $route], $mapping), $priority); } } $result = []; while (!$parsed->isEmpty()) { $result[] = $parsed->extract(); } return $result; }
/** * Поиск кратчайшего пути * @see https://www.youtube.com/watch?v=UA6aV1XJCGg */ private function _shortestPath() { while (!$this->_nodeQueue->isEmpty()) { $u = $this->_nodeQueue->extract(); if (!empty($this->_routes[$u])) { foreach ($this->_routes[$u] as $v => $cost) { $newCost = $this->_destinations[$u] + $cost; if ($newCost < $this->_destinations[$v]) { $this->_destinations[$v] = $newCost; $this->_predecessors[$v] = $u; } } } } }
private function findNeighbors($type, $keywords, $id) { $queue = new SplPriorityQueue(); $queue->setExtractFlags(SplPriorityQueue::EXTR_BOTH); $cursor = $this->m->websites->find([]); foreach ($cursor as $doc) { if ($doc['_id'] != new MongoId($id)) { $d = $this->distance($type, $keywords, $doc['type'], $doc['keywords']); $queue->insert($doc, $d); } } $res = []; for ($i = 0; $i < 20 && !$queue->isEmpty(); $i++) { $res[] = $queue->extract(); } return $res; }
/** * @return int Milliseconds until next timer expires or -1 if there are no pending times. */ private function getTimeout() { while (!$this->timerQueue->isEmpty()) { list($watcher, $expiration) = $this->timerQueue->top(); $id = $watcher->id; if (!isset($this->timerExpires[$id]) || $expiration !== $this->timerExpires[$id]) { $this->timerQueue->extract(); // Timer was removed from queue. continue; } $expiration -= (int) (\microtime(true) * self::MILLISEC_PER_SEC); if ($expiration < 0) { return 0; } return $expiration; } return -1; }
/** * {@inheritdoc} */ public final function compileRoutes(RouteCompiler $compiler, RoutingContext $context) : array { $ref = new \ReflectionClass(static::class); $parsed = new \SplPriorityQueue(); foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) { if ($method->isStatic() || !$method->hasReturnType()) { continue; } $type = (string) $method->getReturnType(); if ($type !== Route::class && !\is_subclass_of($type, Route::class)) { continue; } $args = $context->container->populateArguments($method, [], new InjectionPoint(static::class)); $route = $this->{$method->name}(...$args); foreach ($route->compile($compiler) as list($priority, $depth, $route, $regex, $mapping)) { $parsed->insert(\array_merge([$regex, $depth, $priority, $route], $mapping), $priority); } } $result = []; while (!$parsed->isEmpty()) { $result[] = $parsed->extract(); } return $result; }
public function tokenize(string $input) : array { if (!$this->initialized) { $this->initialized = true; $this->initialize(); } $types = []; $parts = []; $transform = []; foreach ($this->tokens as $k => list($v, $t)) { $types[] = $k; $parts[] = '(' . $v . ')'; $transform[] = $t; } $sorter = new \SplPriorityQueue(); foreach ($this->terminals as $k => list(, $terminal)) { $sorter->insert([$k, $terminal], strlen($terminal)); } while (!$sorter->isEmpty()) { list($k, $terminal) = $sorter->extract(); $types[] = $k; $parts[] = '(' . $terminal . ')'; $transform[] = NULL; } $types[] = 'T_IDENTIFIER'; $parts[] = '(' . $this->identifierPattern . ')'; $transform[] = NULL; $regex = "~" . implode('|', $parts) . "~AS"; $len = strlen($input); $offset = 0; $tokens = []; $line = 1; $pos = 1; $m = NULL; while (true) { if ($offset >= $len) { break; } if (!preg_match($regex, $input, $m, NULL, $offset)) { throw new \RuntimeException(sprintf('No matching token found at position: "%s"', substr($input, $offset, 10))); } $i = count($m) - 2; $type = $types[$i]; $tlen = strlen($m[0]); if ($type === 'T_IDENTIFIER') { $key = strtolower($m[0]); if (isset($this->keywords[$key])) { $keyword = $this->keywords[$key]; if (!$keyword[1] || $m[0] == $keyword[2]) { $type = $keyword[0]; $m[0] = $keyword[2]; } } } if (empty($this->skip[$type])) { $tokens[] = $this->createToken($type, isset($transform[$i]) ? $transform[$i]($m[0]) : $m[0], $line, $pos, $offset + 1); } $offset += $tlen; $pos += $tlen; if (false !== strpos($m[0], "\n")) { $line += substr_count($m[0], "\n"); $pos = strlen(substr($m[0], strrpos($m[0], "\n"))) + 1; } } return $tokens; }
/** * Получить самый дешевый маршрут * * @param string $from Начало маршрута * @param string $to Конец маршрута * * @throws \Exception * * @return array */ public function getPath($from, $to) { /** * Массив с результатом */ $result = []; /** * Массив кратчайших путей к каждому узлу */ $d = []; /** * Массив "предшественников" для каждого узла */ $pi = []; /** * Очередь всех неоптимизированных узлов */ $queue = new SplPriorityQueue(); foreach ($this->graph as $v => $adj) { /** * Устанавливаем изначальные расстояния как бесконечность */ $d[$v] = INF; /** * Никаких узлов позади нет */ $pi[$v] = null; foreach ($adj as $w => $cost) { /** * Воспользуемся ценой связи как приоритетом */ $queue->insert($w, $cost); } } /** * Начальная дистанция на стартовом узле - 0 */ $d[$from] = 0; while (!$queue->isEmpty()) { /** * Извлечем минимальную цену */ $u = $queue->extract(); if (!empty($this->graph[$u])) { /** * Пройдемся по всем соседним узлам */ foreach ($this->graph[$u] as $v => $cost) { /** * Установим новую длину пути для соседнего узла */ $alt = $d[$u] + $cost; /** * Если он оказался короче * update minimum length to vertex установим как минимальное расстояние до этого узла * добавим соседа как предшествующий этому узла */ if ($alt < $d[$v]) { $d[$v] = $alt; $pi[$v] = $u; } } } } /** * Теперь мы можем найти минимальный путь используя обратный проход */ $stack = new SplStack(); $u = $to; $result['sum'] = 0; /** * Проход от целевого узла до стартового */ while (isset($pi[$u]) && $pi[$u]) { $stack->push($u); /** * Добавим стоимость для предшествующих */ $result['sum'] += $this->graph[$u][$pi[$u]]; $u = $pi[$u]; } /** * Стек будет пустой, если нет пути назад */ if ($stack->isEmpty()) { throw new Exception('Нет пути из ' . $from . ' в ' . $to); } else { /** * Добавим стартовый узел и покажем весь путь в обратном (LIFO) порядке */ $stack->push($from); foreach ($stack as $v) { $result['path'][] = $v; } } return $result; }
public function shortestPath($source, $target) { // initialize Q, d and pi for all vertices $d = array(); // array of best estimates of shortest path to each vertex $pi = array(); // array of predecessors for each vertex $Q = new SplPriorityQueue(); // queue of all unoptimized vertices foreach ($this->graph as $v => $adj) { $d[$v] = INF; // set initial distance to "infinity" $pi[$v] = null; // no known predecessors yet foreach ($adj as $w => $cost) { // use the edge cost as the priority $Q->insert($w, $cost); } } // initial distance at source is 0 $d[$source] = 0; while (!$Q->isEmpty()) { // extract min cost $u = $Q->extract(); if (!empty($this->graph[$u])) { // "relax" each adjacent vertex foreach ($this->graph[$u] as $v => $cost) { // alternate route length to adjacent neighbor $alt = $d[$u] + $cost; // if alternate route is shorter if ($alt < $d[$v]) { $d[$v] = $alt; // update minimum length to vertex $pi[$v] = $u; // add neighbor to predecessors for vertex } } } } // we can now find the shortest path using reverse iteration $S = new SplStack(); // construct the shortest path with a stack S $u = $target; $dist = 0; // traverse from target to source while (isset($pi[$u]) && $pi[$u]) { $S->push($u); $dist += $this->graph[$u][$pi[$u]]; // add distance to next predecessor $u = $pi[$u]; } // stack will be empty if there is no route back if ($S->isEmpty()) { echo "No route from {$source} to {$target}\n"; } else { // add the source node and print the path in reverse (LIFO) order $S->push($source); echo "{$dist}:"; $sep = ''; foreach ($S as $v) { echo $sep, $v; $sep = '->'; } echo "\n"; } }
public function shortestPath($source, $target) { $shortPath = array(); //масив найкоротших шляхів $prevNode = array(); //масив попередників $queueNodes = new SplPriorityQueue(); //черга всіх вузлів foreach ($this->graph as $node => $bondage) { $shortPath[$node] = INF; //встановлення початкових шляхів в безкінечність $prevNode[$node] = null; //вузлів позаду немає foreach ($bondage as $bondNode => $cost) { $queueNodes->insert($bondNode, $cost); } } // початкова дистанція на стартовому вузлі - 0 $shortPath[$source] = 0; while (!$queueNodes->isEmpty()) { //вибір мінімальної вартості $node = $queueNodes->extract(); if (!empty($this->graph[$node])) { //прохід по всім сусіднім вузлам foreach ($this->graph[$node] as $nameNode => $cost) { //встановлення нової довжини шляху для сусіднього вузла $alt = $shortPath[$node] + $cost; //якщо вузол коротший if ($alt < $shortPath[$nameNode]) { $shortPath[$nameNode] = $alt; //встановлюється як мінімальна відстань до вузла $prevNode[$nameNode] = $node; //додавання сусіда як попередника вузла } } } } //використовуючи зворотній прохід, визначається мінімальний шлях $shortStack = new SplStack(); //найкоротший шлях як стек $node = $target; $dist = 0; //прохід від цільового вузла до стартового while (isset($prevNode[$node]) && $prevNode[$node]) { $shortStack->push($node); $dist += $this->graph[$node][$prevNode[$node]]; //додавання дистанції для попередників $node = $prevNode[$node]; } //стек буде пустий, якщо нема шляху назад if ($shortStack->isEmpty()) { $this->res .= "Немає шляху із " . $source . " в " . $target; } else { //добавлення стартового вузла, виведення всього шляху $shortStack->push($source); $this->res .= "{$dist}: "; $sep = ''; foreach ($shortStack as $v) { $this->res .= $sep . $v; $sep = '->'; } } return $this->res; }
foreach ($school_array as $key => $school) { $school_same = split(";", $school); $response = json_decode(file_get_contents('http://maps.googleapis.com/maps/api/distancematrix/json?origins=' . urlencode($home) . '&destinations=' . urlencode($school_same[0]) . '&mode=driving&language=nl-BE&sensor=false')); $distance = -(int) $response->rows[0]->elements[0]->distance->text; $pq->insert($school, $distance); $pref_array2[$id][$school] = $distance; } $pref_array[$id] = $pq; } $engage_array = []; $avn_array = []; $id_enagage = []; while (count($engage_array) < count($school_array)) { foreach ($pref_array as $id => $pq) { if (!isset($id_enagage[$id]) || !$id_enagage[$id]) { if (!$pq->isEmpty()) { $top = $pq->top(); if (!isset($engage_array[$top])) { $engage_array[$top] = $id; $id_enagage[$id] = true; //echo "$top***$id<br>"; } else { $old = $engage_array[$top]; if (!isset($avnarray[$old])) { $avnarray[$old] = avn($old, $conn, $pref_array2, $id_home); //echo "###$avnarray[$old]<br>"; } if (!isset($avnarray[$id])) { $avnarray[$id] = avn($id, $conn, $pref_array2, $id_home); //echo "!!!!!$avnarray[$id]<br>"; }
<?php $pq = new SplPriorityQueue(); $pq->insert('Clear drains', 3); $pq->insert('Feed cat', 4); $pq->insert('Make tea', 5); $pq->insert('Solve RC tasks', 1); $pq->insert('Tax return', 2); // This line causes extract() to return both the data and priority (in an associative array), // Otherwise it would just return the data $pq->setExtractFlags(SplPriorityQueue::EXTR_BOTH); while (!$pq->isEmpty()) { print_r($pq->extract()); }