Topologisk sortering
Topologisk sortering för Regisserad acyklisk graf (DAG) är en linjär ordning av hörn så att för varje riktad kant u-v, vertex i kommer före i i beställningen.
Notera: Topologisk sortering för en graf är inte möjlig om grafen inte är en DAG .
Exempel:
Rekommenderad praxis DFS-baserad lösning för att hitta en topologisk sort har redan diskuterats.Inmatning: Graf :
![]()
Exempel
Produktion: 5 4 2 3 1 0
Förklaring: Den första vertexen i topologisk sortering är alltid en vertex med en in-grad på 0 (en vertex utan inkommande kanter). En topologisk sortering av följande graf är 5 4 2 3 1 0. Det kan finnas mer än en topologisk sortering för en graf. En annan topologisk sortering av följande graf är 4 5 2 3 1 0.
Topologisk ordning kanske inte är unik:
Topologisk sortering är ett beroendeproblem där slutförandet av en uppgift beror på slutförandet av flera andra uppgifter vars ordningsföljd kan variera. Låt oss förstå detta koncept med ett exempel:
Anta att vår uppgift är att nå vår skola och för att nå dit måste vi först klä på oss. Beroendena att bära kläder visas i beroendediagrammet nedan. Till exempel kan du inte bära skor innan du bär strumpor.
![]()
Från bilden ovan skulle du redan ha insett att det finns flera sätt att klä på sig, bilden nedan visar några av dessa sätt.
![]()
Kan du lista all möjlig topologisk ordning av att klä på sig för ovanstående beroendediagram?
Algoritm för topologisk sortering med DFS:
Här är en steg-för-steg-algoritm för topologisk sortering med Depth First Search (DFS):
- Skapa en graf med n hörn och m -riktade kanter.
- Initiera en stack och en besökt array av storlek n .
- Gör följande för varje obesökt hörn i grafen:
- Anropa DFS-funktionen med vertex som parameter.
- I DFS-funktionen markerar du vertexet som besökt och anropar DFS-funktionen rekursivt för alla obesökta grannar till vertexet.
- När alla grannar har besökts trycker du spetsen på traven.
- När allt kommer omkring, hörn har besökts, poppar element från stacken och lägg till dem i utdatalistan tills stacken är tom.
- Den resulterande listan är den topologiskt sorterade ordningen för grafen.
Illustration Topologisk sorteringsalgoritm:
Bilden nedan är en illustration av ovanstående tillvägagångssätt:
Övergripande arbetsflöde av topologisk sortering
Steg 1:
- Vi startar DFS från nod 0 eftersom den har noll inkommande noder
- Vi trycker på nod 0 i stacken och flyttar till nästa nod som har minsta antal intilliggande noder, dvs nod 1.
![]()
Steg 2:
- I det här steget, eftersom det inte finns någon angränsande till denna nod, tryck nod 1 i stacken och flytta till nästa nod.
![]()
Steg 3:
- I det här steget väljer vi nod 2 eftersom den har minsta antal intilliggande noder efter 0 och 1.
- Vi anropar DFS för nod 2 och trycker på alla noder som kommer i korsning från nod 2 i omvänd ordning.
- Så tryck 3 och tryck sedan 2 .
![]()
Steg 4:
- Vi kallar nu DFS för nod 4
- Eftersom 0 och 1 redan finns i stacken så vi trycker bara på nod 4 i stacken och går tillbaka.
![]()
Steg 5:
- I detta steg, eftersom alla intilliggande noder av 5 redan finns i stacken, trycker vi nod 5 i stacken och går tillbaka.
![]()
Steg 6: Detta är det sista steget i den topologiska sorteringen där vi poppar alla element från stapeln och skriver ut det i den ordningen.
Nedan är implementeringen av ovanstående tillvägagångssätt:
C++ #include using namespace std; // Function to perform DFS and topological sorting void topologicalSortUtil(int v, vector >& adj, vektor & besökte, stack & Stack) { // Markera den aktuella noden som besökt besökt[v] = sant; // Återkommande för alla angränsande hörn för (int i : adj[v]) { if (!besökt[i]) topologicalSortUtil(i, adj, besökt, Stack); } // Tryck aktuell vertex till stack som lagrar resultatet Stack.push(v); } // Funktion för att utföra Topological Sort void topologicalSort(vector >& adj, int V) { stack Stack; // Stapla för att lagra resultatvektorn besökt(V, falskt); // Anropa den rekursiva hjälpfunktionen för att lagra // Topologisk sortering med början från alla hörn en efter // en för (int i = 0; i < V; i++) { if (!visited[i]) topologicalSortUtil(i, adj, visited, Stack); } // Print contents of stack while (!Stack.empty()) { cout < < Stack.top() < < ' '; Stack.pop(); } } int main() { // Number of nodes int V = 4; // Edges vector > kanter = { { 0, 1 }, { 1, 2 }, { 3, 1 }, { 3, 2 } }; // Graf representerad som en angränsande listvektor > adj(V); for (auto i : kanter) { adj[i[0]].push_back(i[1]); } cout < < 'Topological sorting of the graph: '; topologicalSort(adj, V); return 0; }
Java import java.util.*; public class TopologicalSort { // Function to perform DFS and topological sorting static void topologicalSortUtil(int v, List > adj, boolesk[] besökt, Stack stack) { // Markera den aktuella noden som besökt besökt[v] = sant; // Återkommande för alla angränsande hörn för (int i : adj.get(v)) { if (!besökt[i]) topologicalSortUtil(i, adj, besökt, stack); } // Tryck aktuell vertex till stack som lagrar //-resultatet stack.push(v); } // Funktion för att utföra Topological Sort static void topologicalSort(List > adj, int V) { // Stack för att lagra resultatet Stack stack = ny stack(); boolean[] besökt = new boolean[V]; // Anropa den rekursiva hjälpfunktionen för att lagra // Topologisk sortering med början från alla hörn en // i taget för (int i = 0; i < V; i++) { if (!visited[i]) topologicalSortUtil(i, adj, visited, stack); } // Print contents of stack System.out.print( 'Topological sorting of the graph: '); while (!stack.empty()) { System.out.print(stack.pop() + ' '); } } // Driver code public static void main(String[] args) { // Number of nodes int V = 4; // Edges List > edges = new ArrayList(); edges.add(Arrays.asList(0, 1)); edges.add(Arrays.asList(1, 2)); edges.add(Arrays.asList(3, 1)); edges.add(Arrays.asList(3, 2)); // Grafen representerad som en lista över angränsande listor > adj = ny ArrayList(V); för (int i = 0; i < V; i++) { adj.add(new ArrayList()); } for (List i : edges) { adj.get(i.get(0)).add(i.get(1)); } topologicalSort(adj, V); } }
Python3 def topologicalSortUtil(v, adj, visited, stack): # Mark the current node as visited visited[v] = True # Recur for all adjacent vertices for i in adj[v]: if not visited[i]: topologicalSortUtil(i, adj, visited, stack) # Push current vertex to stack which stores the result stack.append(v) # Function to perform Topological Sort def topologicalSort(adj, V): # Stack to store the result stack = [] visited = [False] * V # Call the recursive helper function to store # Topological Sort starting from all vertices one by # one for i in range(V): if not visited[i]: topologicalSortUtil(i, adj, visited, stack) # Print contents of stack print('Topological sorting of the graph:', end=' ') while stack: print(stack.pop(), end=' ') # Driver code if __name__ == '__main__': # Number of nodes V = 4 # Edges edges = [[0, 1], [1, 2], [3, 1], [3, 2]] # Graph represented as an adjacency list adj = [[] for _ in range(V)] for i in edges: adj[i[0]].append(i[1]) topologicalSort(adj, V) C# using System; using System.Collections.Generic; class Program { // Function to perform DFS and topological sorting static void TopologicalSortUtil(int v, List > adj, bool[] besökt, Stack stack) { // Markera den aktuella noden som besökt besökt[v] = sant; // Återkommande för alla intilliggande hörn foreach(int i i adj[v]) { if (!besökt[i]) TopologicalSortUtil(i, adj, besökt, stack); } // Tryck aktuell vertex till stack som lagrar //-resultatstacken.Push(v); } // Funktion för att utföra Topological Sort static void TopologicalSort(List > adj, int V) { // Stack för att lagra resultatet Stack stack = ny stack (); bool[] besökt = ny bool[V]; // Anropa den rekursiva hjälpfunktionen för att lagra // Topologisk sortering med början från alla hörn en // i taget för (int i = 0; i < V; i++) { if (!visited[i]) TopologicalSortUtil(i, adj, visited, stack); } // Print contents of stack Console.Write('Topological sorting of the graph: '); while (stack.Count>0) { Console.Write(stack.Pop() + ' '); } } // Driver code static void Main(string[] args) { // Antal noder int V = 4; // Kantlista > kanter = ny lista >{ ny lista { 0, 1 }, ny lista { 1, 2 }, ny lista { 3, 1 }, ny lista { 3, 2 } }; // Grafen representerad som en lista över angränsande listor > adj = ny lista >(); för (int i = 0; i < V; i++) { adj.Add(new List ()); } foreach(List i i kanter) { adj[i[0]].Add(i[1]); } TopologicalSort(adj, V); } }
Javascript // Function to perform DFS and topological sorting function topologicalSortUtil(v, adj, visited, stack) { // Mark the current node as visited visited[v] = true; // Recur for all adjacent vertices for (let i of adj[v]) { if (!visited[i]) topologicalSortUtil(i, adj, visited, stack); } // Push current vertex to stack which stores the result stack.push(v); } // Function to perform Topological Sort function topologicalSort(adj, V) { // Stack to store the result let stack = []; let visited = new Array(V).fill(false); // Call the recursive helper function to store // Topological Sort starting from all vertices one by // one for (let i = 0; i < V; i++) { if (!visited[i]) topologicalSortUtil(i, adj, visited, stack); } // Print contents of stack console.log('Topological sorting of the graph: '); while (stack.length>0) { console.log(stack.pop() + ' '); } } // Förarkod (() => { // Antal noder const V = 4; // Edges const edges = [[0, 1], [1, 2], [3, 1], [3, 2]]; // Graph representerad som en adjacency list const adj = Array.from({ length: V }, () => []); (i[1]); } topologicalSort(adj, V })(); Produktion
Topological sorting of the graph: 3 0 1 2
Tidskomplexitet: O(V+E). Algoritmen ovan är helt enkelt DFS med en extra stack. Så tidskomplexitet är detsamma som DFS
Extra utrymme: O(V). Det extra utrymmet behövs för stapeln
Topologisk sortering med BFS:
C++ #include #include #include using namespace std; // Class to represent a graph class Graph { int V; // No. of vertices list * adj; // Pekare till en array som innehåller // adjacency lists public: Graph(int V); // Konstruktör void addEdge(int v, int w); // Funktion för att lägga till en kant till grafen void topologicalSort(); // skriver ut en topologisk sort av // hela grafen }; Graph::Graph(int V) { this->V = V; adj = ny lista [V]; } void Graph::addEdge(int v, int w) { adj[v].push_back(w); // Lägg till w till vs lista. } // Funktion för att utföra Topological Sort void Graph::topologicalSort() { // Skapa en vektor för att lagra i grader av alla vertexvektorer in_degree(V, 0); // Gå igenom närliggande listor för att fylla i_grad av // hörn för (int v = 0; v < V; ++v) { for (auto const& w : adj[v]) in_degree[w]++; } // Create a queue and enqueue all vertices with // in-degree 0 queue q; för (int i = 0; i < V; ++i) { if (in_degree[i] == 0) q.push(i); } // Initialize count of visited vertices int count = 0; // Create a vector to store topological order vector top_order; // En efter en dequeue vertices from queue and enqueue // angränsande hörn om in-degree of adjacent blir 0 medan (!q.empty()) { // Extrahera framsidan av kön (eller utför dequeue) // och lägg till den till topologisk ordning int u = q.front(); q.pop(); top_order.push_back(u); // Iterera genom alla dess närliggande noder // av nod u från kö och minska deras in-grad // med 1 lista ::iterator itr; for (itr = adj[u].begin(); itr != adj[u].end(); ++itr) // Om in-graden blir noll, lägg till den i kön if (--in_degree[*itr) ] == 0) q.push(*itr); räkna++; } // Kontrollera om det fanns en cykel if (count != V) { cout < < 'Graph contains cycle
'; return; } // Print topological order for (int i : top_order) cout < < i < < ' '; } // Driver code int main() { // Create a graph given in the above diagram Graph g(6); g.addEdge(5, 2); g.addEdge(5, 0); g.addEdge(4, 0); g.addEdge(4, 1); g.addEdge(2, 3); g.addEdge(3, 1); cout < < 'Following is a Topological Sort of the given ' 'graph
'; g.topologicalSort(); return 0; } Java import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; // Class to represent a graph class Graph { private int V; // No. of vertices private ArrayList [] adj; // Adjacency list // representation of // the graph // Constructor Graph(int V) { this.V = V; adj = ny ArrayList[V]; för (int i = 0; i < V; ++i) adj[i] = new ArrayList(); } // Function to add an edge to the graph void addEdge(int v, int w) { adj[v].add(w); // Add w to v’s list. } // Function to perform Topological Sort void topologicalSort() { // Create an array to store in-degree of all // vertices int[] inDegree = new int[V]; // Calculate in-degree of each vertex for (int v = 0; v < V; ++v) { for (int w : adj[v]) { inDegree[w]++; } } // Create a queue and enqueue all vertices with // in-degree 0 Queue q = new LinkedList(); för (int i = 0; i < V; ++i) { if (inDegree[i] == 0) q.add(i); } // Initialize count of visited vertices int count = 0; // Create an ArrayList to store topological order ArrayList topOrder = new ArrayList(); // En efter en avköa hörn från kön och // ställ in angränsande hörn i kö om in-graden av // adjacent blir 0 medan (!q.isEmpty()) { // Extrahera köns framsida och lägg till den i // topologisk ordning int u = q.poll(); topOrder.add(u); räkna++; // Iterera genom alla dess närliggande noder av // ur kö nod u och minska deras in-grad // med 1 för (int w : adj[u]) { // Om in-graden blir noll, lägg till den i //-kön if (-inDegree[w] == 0) q.add(w); } } // Kontrollera om det fanns en cykel if (count != V) { System.out.println('Graf innehåller cykel'); lämna tillbaka; } // Skriv ut topologisk ordning för (int i : topOrder) System.out.print(i + ' '); } } // Driver code public class Main { public static void main(String[] args) { // Skapa en graf som ges i diagrammet ovan. Graph g = new Graph(6); g.addEdge(5, 2); g.addEdge(5, 0); g.addEdge(4, 0); g.addEdge(4, 1); g.addEdge(2, 3); g.addEdge(3, 1); System.out.println( 'Följande är en topologisk sortering av den givna grafen'); g.topologicalSort(); } } Python3 from collections import defaultdict class Graph: def __init__(self, vertices): # Number of vertices self.V = vertices # Dictionary to store adjacency lists self.adj = defaultdict(list) def addEdge(self, u, v): # Function to add an edge to the graph self.adj[u].append(v) def topologicalSort(self): # Function to perform Topological Sort # Create a list to store in-degree of all vertices in_degree = [0] * self.V # Traverse adjacency lists to fill in_degree of vertices for i in range(self.V): for j in self.adj[i]: in_degree[j] += 1 # Create a queue and enqueue all vertices with in-degree 0 q = [] for i in range(self.V): if in_degree[i] == 0: q.append(i) # Initialize count of visited vertices count = 0 # Create a list to store topological order top_order = [] # One by one dequeue vertices from queue and enqueue # adjacent vertices if in-degree of adjacent becomes 0 while q: # Extract front of queue (or perform dequeue) # and add it to topological order u = q.pop(0) top_order.append(u) # Iterate through all its neighbouring nodes # of dequeued node u and decrease their in-degree # by 1 for node in self.adj[u]: # If in-degree becomes zero, add it to queue in_degree[node] -= 1 if in_degree[node] == 0: q.append(node) count += 1 # Check if there was a cycle if count != self.V: print('Graph contains cycle') return # Print topological order print('Topological Sort:', top_order) # Driver code if __name__ == '__main__': # Create a graph given in the above diagram g = Graph(6) g.addEdge(5, 2) g.addEdge(5, 0) g.addEdge(4, 0) g.addEdge(4, 1) g.addEdge(2, 3) g.addEdge(3, 1) print('Following is a Topological Sort of the given graph') g.topologicalSort() JavaScript // Class to represent a graph class Graph { constructor(V) { this.V = V; // No. of vertices this.adj = new Array(V); // Array containing adjacency lists for (let i = 0; i < V; i++) { this.adj[i] = []; } } // Function to add an edge to the graph addEdge(v, w) { this.adj[v].push(w); // Add w to v’s list. } // Function to perform Topological Sort topologicalSort() { // Create a array to store in-degree of all vertices let inDegree = new Array(this.V).fill(0); // Traverse adjacency lists to fill inDegree of vertices for (let v = 0; v < this.V; v++) { for (let w of this.adj[v]) { inDegree[w]++; } } // Create a queue and enqueue all vertices with in-degree 0 let queue = []; for (let i = 0; i < this.V; i++) { if (inDegree[i] === 0) { queue.push(i); } } // Initialize count of visited vertices let count = 0; // Create an array to store topological order let topOrder = []; // One by one dequeue vertices from queue and enqueue // adjacent vertices if in-degree of adjacent becomes 0 while (queue.length !== 0) { // Extract front of queue and add it to topological order let u = queue.shift(); topOrder.push(u); // Iterate through all its neighboring nodes // of dequeued node u and decrease their in-degree by 1 for (let w of this.adj[u]) { // If in-degree becomes zero, add it to queue if (--inDegree[w] === 0) { queue.push(w); } } count++; } // Check if there was a cycle if (count !== this.V) { console.log('Graph contains cycle'); return; } // Print topological order console.log('Topological Sort of the given graph:'); console.log(topOrder.join(' ')); } } // Driver code // Create a graph given in the above diagram let g = new Graph(6); g.addEdge(5, 2); g.addEdge(5, 0); g.addEdge(4, 0); g.addEdge(4, 1); g.addEdge(2, 3); g.addEdge(3, 1); console.log('Following is a Topological Sort of the given graph:'); g.topologicalSort(); //This code is contributed by Utkarsh Produktion
Following is a Topological Sort of the given graph 4 5 2 0 3 1
Tidskomplexitet:
Tidskomplexiteten för att konstruera grafen är O(V + E), där V är antalet hörn och E är antalet kanter.
Tidskomplexiteten för att utföra topologisk sortering med BFS är också O(V + E), där V är antalet hörn och E är antalet kanter. Detta beror på att varje vertex och varje kant besöks en gång under BFS-genomgången.
Utrymmes komplexitet:
Utrymmeskomplexiteten för att lagra grafen med hjälp av en närliggande lista är O(V + E), där V är antalet hörn och E är antalet kanter.
Ytterligare utrymme används för att lagra in-graden av hörn, vilket kräver O(V) utrymme.
En kö används för BFS-traversal, som kan innehålla högst V-punkt. Sålunda är utrymmeskomplexiteten för kön O(V).
Totalt sett är rymdkomplexiteten för algoritmen O(V + E) på grund av lagringen av grafen, in-gradersmatrisen och kön.
Sammanfattningsvis är tidskomplexiteten för den tillhandahållna implementeringen O(V + E), och rymdkomplexiteten är också O(V + E).
Notera: Här kan vi också använda en array istället för stacken. Om arrayen används, skriv ut elementen i omvänd ordning för att få den topologiska sorteringen.
Fördelar med topologisk sortering:
- Hjälper till att schemalägga uppgifter eller händelser baserat på beroenden.
- Upptäcker cykler i en riktad graf.
- Effektiv för att lösa problem med prioritetsbegränsningar.
Nackdelar med topologisk sortering:
- Gäller endast riktade acykliska grafer (DAGs), inte lämpliga för cykliska grafer.
- Kanske inte är unik, flera giltiga topologiska ordningar kan existera.
- Ineffektivt för stora grafer med många noder och kanter.
Tillämpningar av topologisk sort:
- Uppgiftsschemaläggning och projektledning.
- Beroendelösning i pakethanteringssystem.
- Bestämma ordningen för kompilering i mjukvarubyggsystem.
- Detektering av dödläge i operativsystem.
- Kursplanering vid universitet.
Relaterade artiklar:
- Kahns algoritm för topologisk sortering
- Alla topologiska sorter av en riktad acyklisk graf