A fundamental procedure in computer science called topological sorting is used to arrange the nodes in a directed network. This sorting method makes sure that vertex u is placed before vertex v in the sorted order for each directed edge (u, v). Numerous fields, including work scheduling, project planning, and dependency resolution, use topological sorting extensively.
Prerequisites: Loops, Structures, Graphs.
Topological Sorting
Topological Sorting is the process in which the main goal is to find an ordering of vertices in a directed acyclic graph (DAG) that places vertex u before vertex v for any directed edge (u, v). “Topological order” is the name given to this linear arrangement. If a DAG contains cycles, it might not have any topological ordering at all.
For example, a topological sorting of the following graph is “5 4 2 3 1 0”. There can be more than one topological sorting for a graph. Another topological sorting of the following graph is “4 5 2 3 1 0”. The first vertex in topological sorting is always a vertex with an in-degree of 0 (a vertex with no incoming edges).
C Program for Topological Sorting
// C Program to implement Topological Sorting #include <stdbool.h> #include <stdio.h> #include <stdlib.h> // Structure to represent a stack struct Stack {
int data;
struct Stack* next;
}; struct Graph {
int V; // No. of vertices
// Pointer to an array containing adjacency lists
struct List* adj;
}; // Structure to represent a list (adjacency list) struct List {
int data;
struct List* next;
}; // Create a new node for the stack struct Stack* createStackNode( int data)
{ struct Stack* newNode
= ( struct Stack*) malloc ( sizeof ( struct Stack));
newNode->data = data;
newNode->next = NULL;
return newNode;
} // Create a new node for the adjacency list struct List* createListNode( int data)
{ struct List* newNode
= ( struct List*) malloc ( sizeof ( struct List));
newNode->data = data;
newNode->next = NULL;
return newNode;
} // Function to initialize a graph with V vertices struct Graph* createGraph( int V)
{ struct Graph* graph
= ( struct Graph*) malloc ( sizeof ( struct Graph));
graph->V = V;
graph->adj
= ( struct List*) malloc (V * sizeof ( struct List));
for ( int i = 0; i < V; ++i) {
graph->adj[i].next = NULL;
}
return graph;
} // Function to add an edge to the graph void addEdge( struct Graph* graph, int v, int w)
{ struct List* newNode = createListNode(w);
newNode->next = graph->adj[v].next;
graph->adj[v].next = newNode;
} // A recursive function used by topologicalSort void topologicalSortUtil( struct Graph* graph, int v,
bool visited[],
struct Stack** stack)
{ visited[v] = true ;
struct List* current = graph->adj[v].next;
while (current != NULL) {
int adjacentVertex = current->data;
if (!visited[adjacentVertex]) {
topologicalSortUtil(graph, adjacentVertex,
visited, stack);
}
current = current->next;
}
// Push the current vertex to stack which stores the
// result
struct Stack* newNode = createStackNode(v);
newNode->next = *stack;
*stack = newNode;
} // The function to do Topological Sort. It uses recursive // topologicalSortUtil void topologicalSort( struct Graph* graph)
{ struct Stack* stack = NULL;
// Mark all the vertices as not visited
bool * visited = ( bool *) malloc (graph->V * sizeof ( bool ));
for ( int i = 0; i < graph->V; ++i) {
visited[i] = false ;
}
// Call the recursive helper function to store
// Topological Sort starting from all vertices one by
// one
for ( int i = 0; i < graph->V; ++i) {
if (!visited[i]) {
topologicalSortUtil(graph, i, visited, &stack);
}
}
// Print contents of stack
while (stack != NULL) {
printf ( "%d " , stack->data);
struct Stack* temp = stack;
stack = stack->next;
free (temp);
}
// Free allocated memory
free (visited);
free (graph->adj);
free (graph);
} // Driver program to test above functions int main()
{ // Create a graph given in the above diagram
struct Graph* g = createGraph(6);
addEdge(g, 5, 2);
addEdge(g, 5, 0);
addEdge(g, 4, 0);
addEdge(g, 4, 1);
addEdge(g, 2, 3);
addEdge(g, 3, 1);
printf ( "Topological Sorting Order: " );
topologicalSort(g);
return 0;
} |
Topological Sorting Order: 5 4 2 3 1 0
- Time Complexity: O(V+E)., where V is the number of vertices and E is the number of edges. The above algorithm is simply DFS with an extra stack. So time complexity is the same as DFS.
- Auxiliary space: O(V). The extra space is needed for the stack
Applications of Topological Sorting
Topological sorting has numerous real-world applications, including:
- In project management, it helps determine the order in which tasks should be executed to minimize dependencies and improve project efficiency.
- Compilers use topological sorting to resolve dependencies between functions and optimize code generation.
- Package managers like APT and YUM use topological sorting to manage software dependencies efficiently.
- Universities use topological sorting to establish course prerequisites, ensuring that students take courses in the correct order.