/** Dijkstra Algorithm for searching of the shortest path between words $first and $finish
  * https://en.wikipedia.org/wiki/Dijkstra's_algorithm     
  *
  * Gets shortest paths from a word with ID $first to $finish,
  * writes shortest path (distance and path) to arrays while $finish is not marked.
  * 
  * @param int $first a first word in a shortest path
  * @param int $finish a last word in a shortest path
  */
 public static function DijkstraAlgorithmByArray($first, $finish)
 {
     global $LINK_DB;
     if ($first == $finish) {
         return array(0, array($first));
     }
     $vertex_arr = PWRelatedWords::getAllRelatedWords();
     // list of unvisited vertexes generated from list of vertexes having an edge
     if (!in_array($first, $vertex_arr)) {
         return array(0, NULL);
     }
     // search vertexes is not connected with any edge
     $infinity = 1000000;
     foreach ($vertex_arr as $v) {
         $unvisited[$v] = $infinity;
     }
     $unvisited[$first] = 0;
     $edge_table = PWRelatedWords::getTableName();
     // table of related words (words and distance between them)
     $prev_arr = array();
     // list of next-to-last for path from first to last vertexes
     $prev_arr[$first] = NULL;
     $prev = $first;
     $path_len = 0;
     //        $dist_arr = array(); // <key>,<value>: list of distances <value> from $first to <key>
     //        $dist_arr[$first] =0;
     $success = 0;
     // the condition of finding the shortest path in the given vertex ($finish)
     //print "<PRE>";
     $count = 0;
     //print $first;
     //return;
     while (!$success && sizeof($unvisited) && $path_len < $infinity) {
         // until all vertixes will not be visited
         //  && $count<10
         print "<p>" . $count . ": " . sizeof($unvisited);
         //.".-----------------------------</p>";
         //print_r($finish_arr);
         //print_r($len_arr);
         $query = "SELECT * FROM {$edge_table} WHERE lemma_id1='{$prev}' or lemma_id2='{$prev}'";
         // search nearest vertexes to $prev (НЕТ необходимости сортировать, так как неважно в какой последовательности ставятся метки)
         $res_neib = $LINK_DB->query_e($query, "Query failed in file <b>" . __FILE__ . "</b>, string <b>" . __LINE__ . "</b>");
         while ($row_neib = $res_neib->fetch_object()) {
             if ($row_neib->lemma_id1 == $prev) {
                 $last = $row_neib->lemma_id2;
             } else {
                 $last = $row_neib->lemma_id1;
             }
             $new_path_len = $path_len + $row_neib->weight;
             // path length from $prev to $last (neighbour of $prev via semantic relations)
             //                if (!isset($dist_arr[$last]) || $dist_arr[$last]>$new_path_len) { // this is new path from $first to $last OR
             if (isset($unvisited[$last]) && $unvisited[$last] > $new_path_len) {
                 // this is new path from $first to $last OR
                 // already (one) path from $first to $last does exist, but the new path is shorter
                 //                    $dist_arr[$last] =
                 $unvisited[$last] = $new_path_len;
                 $prev_arr[$last] = $prev;
             }
         }
         $count++;
         $path_len = min(array_values($unvisited));
         // choose minimal distance of path from first to any unvisited vertex
         $prev = array_search($path_len, $unvisited);
         // choose unvisited vertex with minimal distance
         print " = " . $path_len;
         unset($unvisited[$prev]);
         // mark this vertes as visited, delete it from unvisited list
         if ($prev == $finish) {
             // the shortest path in $finish are found!!
             $success = 1;
             continue;
         }
     }
     print "<p>{$count} iterations";
     if ($success) {
         //
         $path = array($finish);
         $prev = $prev_arr[$finish];
         while ($prev != NULL) {
             array_unshift($path, $prev);
             $prev = $prev_arr[$prev];
         }
         return array($path_len, $path);
     } else {
         return array(NULL, NULL);
     }
     // any path from $first to $finish are not found
 }