Niedrigster gemeinsamer Vorfahr ähnlicher Algorithmus für ein Diagramm


7

Ich arbeite an einem Typsystem und stoße auf ein Problem, das dem niedrigsten gemeinsamen Vorfahren ähnlich zu sein scheint. Bei zwei Typen muss ich die kleinste Folge von Konvertierungen finden, die zum gleichen Zieltyp führt. Wenn ich einen einfachen Typbaum hätte, weiß ich, wie ich das Ergebnis erhalte, aber leider habe ich eine etwas komplexere Diagrammstruktur.

Diese Grafik enthält einige wichtige Punkte. Es ist unidirektional und es werden niemals Schleifen gebildet. Aufgrund einer unbegrenzten Anzahl von Typen kann es jedoch nicht statisch hergestellt werden. Die Entfernung eines Pfades ist im Allgemeinen recht gering. Es "fühlt" sich eher wie ein Baum mit einer Reihe von Abkürzungskanten an.

Anfangs habe ich mir den niedrigsten gemeinsamen Vorfahren angesehen, aber er wird hauptsächlich als Baumalgorithmus beschrieben. Ich habe die Hoffnung, dass ich sie anpassen könnte, noch nicht aufgegeben. Die andere Möglichkeit wäre ein allgemeinerer Pfadfindungsalgorithmus.

Ich hoffe, jemand hat dieses oder ein ähnliches Problem schon einmal gesehen und kann mir einige Hinweise geben, wie ich es weiter angehen kann. Es kommt mir bekannt vor, dass ich davon ausgehe, dass etwas existieren muss, und ich suche nur nach den falschen Begriffen / Namen.


Hier ist mein Versuch, dies formeller zu beschreiben.

Lass es eine Grafik geben G={V.}} so dass jeder Scheitelpunkt eine Reihe von ausgehenden Kanten hat V.={E.=V.x}}. Da das Diagramm dynamisch und möglicherweise unendlich ist, gibt es keine Möglichkeit, das Formular zu erstellenG={V.,E.=(V.x,V.y)}} für das gesamte Diagramm.

Ein Pfad wird aus einem Scheitelpunkt gebildet, indem einer der verfügbaren Kanten von diesem Knoten gefolgt wird. P.nmx=V.n,...,V.m. Die Länge dieses Pfades entspricht der Anzahl der Eckpunkte in der Sequenz. Es ist kein Zyklus möglich. Die Menge aller Pfade zwischen zwei Knoten wird ausgedrückt alsP.nm={V.n,...,V.m}}.

Beachten Sie, dass P.nmkann in einer endlichen Anzahl von Schritten als leer bestimmt werden. Das Ganze aufzählenP.nm Set ist praktisch nicht möglich.

Das Problem besteht darin, den kürzesten Weg von zwei Scheitelpunkten zu einem dritten Scheitelpunkt zu finden. Das heißt, gegebenV.ein,V.b, finden V.c so dass Pfade P.eincx und P.bcy existieren und lenGth(P.eincx)+lenGth(P.bcy) ist minimal.


1
Ein gerichteter Graph ohne gerichtete Zyklen ist als DAG bekannt. In Ihrem Fall sagen Sie, dass das Diagramm keine Schleifen enthält. Kann es Zyklen enthalten?
Yuval Filmus

1
Können Sie Ihr Problem auch formeller darlegen? Hier ist eine Möglichkeit gegebenx,ySie suchen einen Knoten z das minimiert d(z,x)+d(z,y), wo dist die gerichtete Entfernung. Können Sie bei einem gegebenen Knoten auch alle Kanten aufzählen, die darauf zeigen, dh alle unmittelbaren Vorfahren?
Yuval Filmus

1
Ich hätte angenommen, man muss minimieren maxd(z,x),d(z,y). Existiert Ihr niedrigster Vorfahr in jedem Fall (dh: Gibt es eine "Wurzel" wie java.lang.Object)?
Frafl

Bearbeitet. Bei einem gegebenen Knoten können Sie alle seine unmittelbaren Vorfahren auflisten. Nein, es gibt keine gemeinsame Wurzel und keine Garantie dafür, dass zwei Typen einen gemeinsamen Vorfahren haben.
edA-qa mort-ora-y

1
Beachten Sie, dass "Sie können alle seine unmittelbaren Vorfahren aufzählen" nicht bedeutet, dass die Anzahl der unmittelbaren Vorfahren endlich ist, was Sie wahrscheinlich sagen möchten. Wenn die Regel "Den kürzesten Weg finden" nur als Ad-hoc-Methode zum Auflösen von Mehrdeutigkeiten im Typsystem gedacht ist, kann sich herausstellen, dass sie einige unerwünschte Eigenschaften aufweist. Wenn Sie andererseits zeigen könnten, dass es bei sachgemäßer Verwendung keine unerwünschten Eigenschaften aufweist, wäre dies ein interessantes Ergebnis. Andernfalls wäre die "kleinste Obergrenze" im Poset die natürlichere Interpretation des "niedrigsten gemeinsamen Vorfahren".
Thomas Klimpel

Antworten:


5

Wenn der niedrigste gemeinsame Vorfahr zweier Typen immer existiert und eindeutig ist, ist Ihre Struktur ein Join-Semilattice. Die Berechnung des niedrigsten gemeinsamen Vorfahren ist möglich, aber die Laufzeitkomplexität im schlimmsten Fall ist nicht so gut, wie ich es intuitiv erwartet hätte. Ich habe vor einiger Zeit eine verwandte Frage gestellt , war aber zu faul, um eine Antwort zu schreiben, nachdem ich die relevante Lösung in der "Literatur" gefunden hatte. Ich habe gerade die Antwort geschrieben und sie beginnt wie folgt:

Dieser Blogpost zur Gittertheorie enthält einen nützlichen Referenzabschnitt, der unter anderem "Gittertheorie mit Anwendungen" von Vijay K. Garg enthält. Kapitel 2 "Darstellen von Posets" beschreibt einige Datenstrukturen zum Darstellen von Posets und erläutert, wie die Verknüpfung (x, y) mithilfe einer solchen Datenstruktur berechnet wird.

Hier ist der relevante Teil aus Kapitel 2.3.1:

Wir geben jetzt eine Ö(n+|e|) Algorithmus zur Berechnung der Verbindung zweier Elemente x und y. Der Algorithmus kehrt zurücknullwenn der Join nicht existiert. Wir gehen zunächst davon aus, dass wir die Deckungsrelation verwenden. BerechnenjÖichn(x,y)gehen wir wie folgt vor:

  • Schritt 0: Färben Sie alle Knoten weiß.
  • Schritt 1: Färben Sie alle Knoten aus, die von erreichbar sind xso grau. Dies kann von einem BFS oder einem DFS ausgehend vom Knoten erfolgenx.
  • Schritt 2: Führen Sie ein BFS / DFS vom Knoten aus y. Färben Sie alle grauen Knoten als schwarz.
  • Schritt 3: Wir bestimmen nun für jeden schwarzen Knoten z, die Anzahl der schwarzen Knoten, die auf zeigen z. Ruf diese Nummer anichnB.leinck[z]] für jeden Knoten z. Dieser Schritt kann in ausgeführt werdenÖ(n+|e|) indem Sie die Adjazenzlisten aller schwarzen Knoten durchgehen und die kumulativen Zählungen für beibehalten ichnB.leinck Array.
  • Schritt 4: Wir zählen die Anzahl der schwarzen Knoten z mit ichnB.leinck[z]] gleicht 0. Wenn es genau einen Knoten gibt, geben wir diesen Knoten als Antwort zurück. Ansonsten kehren wir zurücknull.

Diese Antwort interpretiert den "niedrigsten gemeinsamen Vorfahren" in Bezug auf die von der DAG definierte Teilreihenfolge. Für das Lesen in Bezug auf Pfadlängen haben wir kein Halbgitter mehr, aber der Algorithmus kann immer noch angepasst werden, indem nur BFS verwendet und beide Suchvorgänge entsprechend verschachtelt werden. Die Poset-Interpretation ist immer noch nützlich, um festzustellen, ob mindestens ein Kandidat für den "niedrigsten gemeinsamen Vorfahren" existiert.
Thomas Klimpel
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.