2011-01-22 11 views
5

Załóżmy, że dostałem nieukierunkowane drzewo i potrzebuję znaleźć ścieżkę (jedyną ścieżkę) między dwoma węzłami.Ścieżka odnajdywania algorytmu w nienazwanym drzewie

Jaki jest najlepszy algorytm do tego. Prawdopodobnie mógłbym użyć algorytmu Dijkstry, ale prawdopodobnie coś lepszego dla drzew.

C++ Przykładem może być pomocne, ale nie jest to konieczne

Dziękuję

+0

Masz na myśli znalezienie ** ścieżki **. O ile nie pozwala się na wielokrotną ścieżkę przechodzącą przez ten sam węzeł, to istnieje tylko jedna ścieżka z jednego węzła do drugiego w drzewie (jest to faktycznie jedna z możliwych definicji drzewa). – 6502

+0

@ 6502 Tak, oczywiście – Yakov

+0

Wysłałem odpowiedź zakładając, że jesteś zainteresowany również ścieżkami, które są częściowo "w górę", nawet jeśli nie ma żadnych linków do węzła nadrzędnego węzła w twojej reprezentacji. Nie jest to jasne w pytaniu ... – 6502

Odpowiedz

1

Przypuśćmy masz

struct Node 
{ 
    std::vector<Node *> children; 
}; 

następnie co można zrobić przemierza całe drzewo zaczynając od korzenia utrzymując cały łańcuch podczas przechodzenia. Jeśli znajdziesz np. node1 następnie zapisać bieżący łańcuch, jeśli okaże node2 następnie sprawdzić na skrzyżowaniu ... w kodzie (NIETESTOWANY):

bool findPath(std::vector<Node *>& current_path, // back() is node being visited 
       Node *n1, Node *n2,    // interesting nodes 
       std::vector<Node *>& match,  // if not empty back() is n1/n2 
       std::vector<Node *>& result)  // where to store the result 
{ 
    if (current_path.back() == n1 || current_path.back() == n2) 
    { 
     // This is an interesting node... 
     if (match.size()) 
     { 
      // Now is easy: current_path/match are paths from root to n1/n2 
      ... 
      return true; 
     } 
     else 
     { 
      // This is the first interesting node found 
      match = current_path; 
     } 
    } 
    for (std::vector<Node *>::iterator i=current_path.back().children.begin(), 
             e=current_path.back().children.end(); 
     i != e; ++i) 
    { 
     current_path.push_back(*i); 
     if (findPath(current_path, n1, n2, match, result)) 
      return true; 
     current_path.pop_back(); // *i 
    } 
    return false; 
} 
6

Zakładając, każdy węzeł ma wskaźnik do jego rodzica, a potem po prostu śledzić back-up drzewa w kierunku korzenia z każdym uruchomieniu węzła. W końcu obie ścieżki muszą się przecinać. Testowanie dla przecięcia może być tak proste, jak utrzymanie adresów węzłów.

UPDATE

Jak już zaktualizowane pytanie określić nieukierunkowane drzew, to powyższe nie jest ważna. Prostym podejściem jest po prostu wykonanie przejścia od początku do głębi, zaczynając od Węzła # 1, w końcu trafisz Węzeł nr 2. Jest to O (n) w rozmiarze drzewa. Nie jestem pewien, czy będzie szybsze podejście, zakładając zupełnie ogólne drzewo.

+0

Mówię o drzewie niekierowanym – Yakov

+1

@Yakov: Cóż, tak, to wyraźnie robi różnicę! Cieszę się, że odpowiednio zaktualizowałeś swoje pytanie. –

1

Szerokość pierwszego wyszukiwania i głębokość pierwszego wyszukiwania są bardziej skuteczne wtedy Dijkstry algorytm.

+0

Czy Dijksta nie jest identyczna jak szerokość - czy wszystkie wagi brzegowe są jednym (lub bardziej ogólne)? – CodesInChaos

+0

To nie jest. Jeśli używasz Dijkstry, musisz wybrać najbliższe nieodwiedzone skrzyżowanie (jest wolne). Tak więc złożoność to O (E + V logV), E-krawędzie, V - wierzchołki, jeśli używasz sterty Fibonacciego do wydobycia minimum. Jeśli użyjesz opcji "Najpierw szerokość", złożoność to O (E + V) = O (V) (to drzewo, więc E = V - 1). – lacungus

Powiązane problemy