Introductie
In de informatica is een directed acyclic graph (DAG) een gerichte grafiek zonder cycli. In deze tutorial laten we zien hoe u een topologische sortering op een DAG in lineaire tijd kunt uitvoeren.
Topologische sortering
In veel toepassingen gebruiken we gerichte acyclische grafieken om de voorrang tussen gebeurtenissen aan te geven. Bijvoorbeeld, in een planningsprobleem is er een reeks taken en een reeks beperkingen die de volgorde van deze taken specificeren. We kunnen een DAG construeren om taken weer te geven. De gerichte randen van de DAG geven de volgorde van de taken weer.
Laten we eens kijken naar een probleem met hoe een persoon zich zou kunnen kleden voor een formele gelegenheid. We moeten verschillende kledingstukken aantrekken, zoals sokken, broeken, schoenen, enz. Sommige kledingstukken moeten voor de andere worden aangetrokken. Bijvoorbeeld, we moeten eerst sokken aantrekken en dan pas schoenen. Sommige kledingstukken kunnen in willekeurige volgorde worden aangetrokken, bijvoorbeeld sokken en broeken. We kunnen een DAG gebruiken om dit probleem te illustreren:

In deze DAG komen hoekpunten overeen met kledingstukken. Een directe rand  in de DAG geeft aan dat we kledingstuk
 in de DAG geeft aan dat we kledingstuk  moeten aantrekken vóór kledingstuk
 moeten aantrekken vóór kledingstuk  . Onze taak is een volgorde te vinden voor het aantrekken van alle kledingstukken, met inachtneming van de afhankelijkheidsbeperkingen. We kunnen bijvoorbeeld kledingstukken in de volgende volgorde aantrekken:
. Onze taak is een volgorde te vinden voor het aantrekken van alle kledingstukken, met inachtneming van de afhankelijkheidsbeperkingen. We kunnen bijvoorbeeld kledingstukken in de volgende volgorde aantrekken:

Een topologische sortering van een DAG  is een lineaire ordening van al zijn hoekpunten zodanig dat als
 is een lineaire ordening van al zijn hoekpunten zodanig dat als  een rand
 een rand  bevat,
 bevat,  voor
 voor  in de ordening staat. Voor een DAG kunnen we een topologische sortering construeren met een looptijd lineair met het aantal hoekpunten plus het aantal ribben, dat is
 in de ordening staat. Voor een DAG kunnen we een topologische sortering construeren met een looptijd lineair met het aantal hoekpunten plus het aantal ribben, dat is  .
.
Kahn’s Algoritme
In een DAG heeft elk pad tussen twee hoekpunten een eindige lengte omdat de grafiek geen cyclus bevat. Zij  het langste pad van
 het langste pad van  (bronvertex) naar
 (bronvertex) naar  (bestemmingsvertex). Omdat
 (bestemmingsvertex). Omdat  het langste pad is, kan er geen inkomende rand naar
 het langste pad is, kan er geen inkomende rand naar  zijn. Een DAG bevat dus minstens één vertex dat geen inkomende edge heeft.
 zijn. Een DAG bevat dus minstens één vertex dat geen inkomende edge heeft.
3.1. Algoritme van Kahn
In het algoritme van Kahn construeren we een topologische sortering op een DAG door hoekpunten te vinden die geen inkomende ribben hebben:

In dit algoritme berekenen we eerst de in-graadwaarden voor alle hoekpunten.
Daarna beginnen we met een hoekpunt waarvan de in-graad 0 is en plaatsen we het aan het eind van de uitvoerlijst. Zodra we een hoekpunt kiezen, werken we de in-graadwaarden van de aangrenzende hoekpunten bij, omdat het hoekpunt en zijn uitstaande randen uit de grafiek worden verwijderd.
We kunnen het bovenstaande proces herhalen totdat we alle hoekpunten hebben gekozen. De uitvoerlijst is dan een topologische sortering van de grafiek.
3.2. Tijdscomplexiteit
Om de in-graad van alle hoekpunten te berekenen, moeten we alle hoekpunten en ribben van  bezoeken. Daarom is de looptijd
 bezoeken. Daarom is de looptijd  voor in-graad berekeningen. Om te vermijden dat we deze waarden opnieuw moeten berekenen, kunnen we een array gebruiken om de in-graad waarden van deze hoekpunten bij te houden. Binnen de while lus moeten we ook alle hoekpunten en ribben bezoeken. Daarom is de totale looptijd
 voor in-graad berekeningen. Om te vermijden dat we deze waarden opnieuw moeten berekenen, kunnen we een array gebruiken om de in-graad waarden van deze hoekpunten bij te houden. Binnen de while lus moeten we ook alle hoekpunten en ribben bezoeken. Daarom is de totale looptijd  .
.
Depth First Search
We kunnen ook een Depth First Search (DFS) algoritme gebruiken om de topologische sorter te construeren.
4.1. Grafiek DFS met recursie
Voordat we het aspect van de topologische sortering met DFS aanpakken, bekijken we eerst een standaard recursief algoritme voor het doorlopen van de grafiek DFS:

In het standaard DFS-algoritme beginnen we met een willekeurig hoekpunt in  en markeren we dit hoekpunt als bezocht. Vervolgens roepen we recursief de functie dfsRecursive op om alle niet-bezochte aangrenzende hoekpunten te bezoeken. Op deze manier kunnen we alle hoekpunten van
 en markeren we dit hoekpunt als bezocht. Vervolgens roepen we recursief de functie dfsRecursive op om alle niet-bezochte aangrenzende hoekpunten te bezoeken. Op deze manier kunnen we alle hoekpunten van  in
 in  tijd bezoeken.
 tijd bezoeken.
Hoewel, omdat we elk hoekpunt onmiddellijk in de lijst zetten wanneer we het bezoeken, en omdat we bij elk hoekpunt kunnen beginnen, kan het standaard DFS algoritme niet garanderen dat het een topologisch gesorteerde lijst genereert.
Laten we eens kijken wat we moeten doen om deze tekortkoming aan te pakken.
4.2. DFS gebaseerd topologisch sorteeralgoritme
We kunnen het DFS-algoritme aanpassen om een topologische sortering van een DAG te genereren. Tijdens de DFS traversal, nadat alle buren van een hoekpunt  zijn bezocht, zetten we het vooraan in de resultatenlijst
 zijn bezocht, zetten we het vooraan in de resultatenlijst  . Op deze manier kunnen we ervoor zorgen dat
. Op deze manier kunnen we ervoor zorgen dat  voor al zijn buren in de gesorteerde lijst verschijnt:
 voor al zijn buren in de gesorteerde lijst verschijnt:

Dit algoritme is vergelijkbaar met het standaard DFS algoritme. Hoewel we nog steeds beginnen met een willekeurig hoekpunt, zetten we het hoekpunt niet onmiddellijk in de lijst zodra we het bezoeken. In plaats daarvan bezoeken we eerst recursief al zijn buren en zetten het hoekpunt dan vooraan in de lijst. Dus, als  een rand
 een rand  bevat, dan verschijnt
 bevat, dan verschijnt  voor
 voor  in de lijst.
 in de lijst.
De totale looptijd is ook  , want het heeft dezelfde tijdcomplexiteit als het DFS algoritme.
, want het heeft dezelfde tijdcomplexiteit als het DFS algoritme.
Conclusie
In dit artikel hebben we een voorbeeld laten zien van topologisch sorteren op een DAG. Ook hebben we twee algoritmen besproken die een topologische sortering kunnen maken in  tijd.
 tijd.
De Java-implementatie van het op DFS gebaseerde topologische sorteeralgoritme is beschikbaar in ons artikel over Depth First Search in Java.