Clasificación topológica

 

La ordenación topológica para el gráfico acíclico dirigido (DAG) es una ordenación lineal de vértices tal que para cada arista dirigida uv, el vértice u viene antes que v en la ordenación. La clasificación topológica de un gráfico no es posible si el gráfico no es un DAG.

Por ejemplo, una clasificación topológica del siguiente gráfico es «5 4 2 3 1 0». Puede haber más de una clasificación topológica para un gráfico. Por ejemplo, otra clasificación topológica del siguiente gráfico es «4 5 2 3 1 0». El primer vértice en la clasificación topológica siempre es un vértice con grado de entrada 0 (un vértice sin bordes entrantes).
 

graph

Clasificación topológica frente a profundidad primero transversal (DFS)

En DFS , imprimimos un vértice y luego recursivamente llamamos a DFS para sus vértices adyacentes. En la clasificación topológica, necesitamos imprimir un vértice antes que sus vértices adyacentes. Por ejemplo, en el gráfico dado, el vértice ‘5’ debe imprimirse antes del vértice ‘0’, pero a diferencia de DFS , el vértice ‘4’ también debe imprimirse antes del vértice ‘0’. Entonces, la clasificación topológica es diferente de DFS. Por ejemplo, un DFS del gráfico que se muestra es «5 2 3 1 0 4», pero no es una clasificación topológica.

Algoritmo para encontrar la clasificación topológica: 

Recomendamos ver primero la implementación de DFS . Podemos modificar DFS para encontrar la clasificación topológica de un gráfico. En DFS , comenzamos desde un vértice, primero lo imprimimos y luego recursivamente llamamos a DFS para sus vértices adyacentes. En la clasificación topológica, usamos una pila temporal. No imprimimos el vértice de inmediato, primero llamamos recursivamente a la clasificación topológica para todos sus vértices adyacentes y luego lo colocamos en una pila. Finalmente, imprima el contenido de la pila. Tenga en cuenta que un vértice se empuja a la pila solo cuando todos sus vértices adyacentes (y sus vértices adyacentes, etc.) ya están en la pila. 

La siguiente imagen es una ilustración del enfoque anterior:

Topological-Sorting

A continuación se muestran las implementaciones de clasificación topológica. Consulte el código de profundidad de primer recorrido para un gráfico desconectado y tenga en cuenta las diferencias entre el segundo código que se proporciona allí y el siguiente código.

C++

// A C++ program to print topological
// sorting of a DAG
#include <iostream>
#include <list>
#include <stack>
using namespace std;
 
// Class to represent a graph
class Graph {
    // No. of vertices'
    int V;
 
    // Pointer to an array containing adjacency listsList
    list<int>* adj;
 
    // A function used by topologicalSort
    void topologicalSortUtil(int v, bool visited[],
                             stack<int>& Stack);
 
public:
    // Constructor
    Graph(int V);
 
    // function to add an edge to graph
    void addEdge(int v, int w);
 
    // prints a Topological Sort of
    // the complete graph
    void topologicalSort();
};
 
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
}
 
void Graph::addEdge(int v, int w)
{
    // Add w to v’s list.
    adj[v].push_back(w);
}
 
// A recursive function used by topologicalSort
void Graph::topologicalSortUtil(int v, bool visited[],
                                stack<int>& Stack)
{
    // Mark the current node as visited.
    visited[v] = true;
 
    // Recur for all the vertices
    // adjacent to this vertex
    list<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            topologicalSortUtil(*i, visited, Stack);
 
    // Push current vertex to stack
    // which stores result
    Stack.push(v);
}
 
// The function to do Topological Sort.
// It uses recursive topologicalSortUtil()
void Graph::topologicalSort()
{
    stack<int> Stack;
 
    // Mark all the vertices as not visited
    bool* visited = new bool[V];
    for (int i = 0; i < 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 < V; i++)
        if (visited[i] == false)
            topologicalSortUtil(i, visited, Stack);
 
    // Print contents of stack
    while (Stack.empty() == false) {
        cout << Stack.top() << " ";
        Stack.pop();
    }
}
 
// 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 \n";
 
    // Function Call
    g.topologicalSort();
 
    return 0;
}

Java

// A Java program to print topological
// sorting of a DAG
import java.io.*;
import java.util.*;
 
// This class represents a directed graph
// using adjacency list representation
class Graph {
    // No. of vertices
    private int V;
 
    // Adjacency List as ArrayList of ArrayList's
    private ArrayList<ArrayList<Integer> > adj;
 
    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new ArrayList<ArrayList<Integer> >(v);
        for (int i = 0; i < v; ++i)
            adj.add(new ArrayList<Integer>());
    }
 
    // Function to add an edge into the graph
    void addEdge(int v, int w) { adj.get(v).add(w); }
 
    // A recursive function used by topologicalSort
    void topologicalSortUtil(int v, boolean visited[],
                             Stack<Integer> stack)
    {
        // Mark the current node as visited.
        visited[v] = true;
        Integer i;
 
        // Recur for all the vertices adjacent
        // to thisvertex
        Iterator<Integer> it = adj.get(v).iterator();
        while (it.hasNext()) {
            i = it.next();
            if (!visited[i])
                topologicalSortUtil(i, visited, stack);
        }
 
        // Push current vertex to stack
        // which stores result
        stack.push(new Integer(v));
    }
 
    // The function to do Topological Sort.
    // It uses recursive topologicalSortUtil()
    void topologicalSort()
    {
        Stack<Integer> stack = new Stack<Integer>();
 
        // Mark all the vertices as not visited
        boolean visited[] = new boolean[V];
        for (int i = 0; i < 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 < V; i++)
            if (visited[i] == false)
                topologicalSortUtil(i, visited, stack);
 
        // Print contents of stack
        while (stack.empty() == false)
            System.out.print(stack.pop() + " ");
    }
 
    // Driver code
    public static void main(String args[])
    {
        // Create a graph given in the above diagram
        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("Following is a Topological "
                           + "sort of the given graph");
        // Function Call
        g.topologicalSort();
    }
}
// This code is contributed by Aakash Hasija

Python3

# Python program to print topological sorting of a DAG
from collections import defaultdict
 
# Class to represent a graph
 
 
class Graph:
    def __init__(self, vertices):
        self.graph = defaultdict(list)  # dictionary containing adjacency List
        self.V = vertices  # No. of vertices
 
    # function to add an edge to graph
    def addEdge(self, u, v):
        self.graph[u].append(v)
 
    # A recursive function used by topologicalSort
    def topologicalSortUtil(self, v, visited, stack):
 
        # Mark the current node as visited.
        visited[v] = True
 
        # Recur for all the vertices adjacent to this vertex
        for i in self.graph[v]:
            if visited[i] == False:
                self.topologicalSortUtil(i, visited, stack)
 
        # Push current vertex to stack which stores result
        stack.append(v)
 
    # The function to do Topological Sort. It uses recursive
    # topologicalSortUtil()
    def topologicalSort(self):
        # Mark all the vertices as not visited
        visited = [False]*self.V
        stack = []
 
        # Call the recursive helper function to store Topological
        # Sort starting from all vertices one by one
        for i in range(self.V):
            if visited[i] == False:
                self.topologicalSortUtil(i, visited, stack)
 
        # Print contents of the stack
        print(stack[::-1])  # return list in reverse order
 
 
# Driver Code
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")
 
# Function Call
g.topologicalSort()
 
# This code is contributed by Neelam Yadav

C#

// A C# program to print topological
// sorting of a DAG
using System;
using System.Collections.Generic;
 
// This class represents a directed graph
// using adjacency list representation
class Graph {
 
    // No. of vertices
    private int V;
 
    // Adjacency List as ArrayList
    // of ArrayList's
    private List<List<int> > adj;
 
    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new List<List<int> >(v);
        for (int i = 0; i < v; i++)
            adj.Add(new List<int>());
    }
 
    // Function to add an edge into the graph
    public void AddEdge(int v, int w) { adj[v].Add(w); }
 
    // A recursive function used by topologicalSort
    void TopologicalSortUtil(int v, bool[] visited,
                             Stack<int> stack)
    {
 
        // Mark the current node as visited.
        visited[v] = true;
 
        // Recur for all the vertices
        // adjacent to this vertex
        foreach(var vertex in adj[v])
        {
            if (!visited[vertex])
                TopologicalSortUtil(vertex, visited, stack);
        }
 
        // Push current vertex to
        // stack which stores result
        stack.Push(v);
    }
 
    // The function to do Topological Sort.
    // It uses recursive topologicalSortUtil()
    void TopologicalSort()
    {
        Stack<int> stack = new Stack<int>();
 
        // Mark all the vertices as not visited
        var visited = new bool[V];
 
        // Call the recursive helper function
        // to store Topological Sort starting
        // from all vertices one by one
        for (int i = 0; i < V; i++) {
            if (visited[i] == false)
                TopologicalSortUtil(i, visited, stack);
        }
 
        // Print contents of stack
        foreach(var vertex in stack)
        {
            Console.Write(vertex + " ");
        }
    }
 
    // Driver code
    public static void Main(string[] args)
    {
 
        // Create a graph given
        // in the above diagram
        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);
 
        Console.WriteLine("Following is a Topological "
                          + "sort of the given graph");
 
        // Function Call
        g.TopologicalSort();
    }
}
 
// This code is contributed by Abhinav Galodha

Javascript

<script>
 
// Javascript for the above approach
 
    // This class represents a directed graph
    // using adjacency list representation
    class Graph{
 
        // Constructor
        constructor(v)
        {
            // Number of vertices
            this.V = v
 
            // Adjacency List as ArrayList of ArrayList's
            this.adj = new Array(this.V)
            for (let i = 0 ; i < this.V ; i+=1){
                this.adj[i] = new Array()
            }
        }
 
        // Function to add an edge into the graph
        addEdge(v, w){
            this.adj[v].push(w)
        }
 
        // A recursive function used by topologicalSort
        topologicalSortUtil(v, visited, stack)
        {
            // Mark the current node as visited.
            visited[v] = true;
            let i = 0;
 
            // Recur for all the vertices adjacent
            // to thisvertex
            for(i = 0 ; i < this.adj[v].length ; i++){
                if(!visited[this.adj[v][i]]){
                    this.topologicalSortUtil(this.adj[v][i], visited, stack)
                }
            }
 
            // Push current vertex to stack
            // which stores result
            stack.push(v);
        }
 
        // The function to do Topological Sort.
        // It uses recursive topologicalSortUtil()
        topologicalSort()
        {
            let stack = new Array()
 
            // Mark all the vertices as not visited
            let visited = new Array(this.V);
            for (let i = 0 ; i < this.V ; i++){
                visited[i] = false;
            }
 
            // Call the recursive helper
            // function to store
            // Topological Sort starting
            // from all vertices one by one
            for (let i = 0 ; i < this.V ; i++){
                if (visited[i] == false){
                    this.topologicalSortUtil(i, visited, stack);
                }
            }
 
            // Print contents of stack
            while (stack.length != 0){
                console.log(stack.pop() + " ")
            }
        }
    }
 
    // Driver Code
    var 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")
     
    // Function Call
    g.topologicalSort()
     
    // This code is contributed by subhamgoyal2014.
</script>
Producción

Following is a Topological Sort of the given graph 
5 4 2 3 1 0 

Análisis de Complejidad: 

  • Complejidad Temporal: O(V+E). 
    El algoritmo anterior es simplemente DFS con una pila extra. Entonces, la complejidad del tiempo es la misma que la DFS, que es.
  • Espacio auxiliar: O(V). 
    El espacio extra es necesario para la pila.

Nota: Aquí, también podemos usar vector en lugar de la pila. Si se usa el vector, imprima los elementos en orden inverso para obtener la clasificación topológica.

Aplicaciones: 
la clasificación topológica se utiliza principalmente para programar trabajos a partir de las dependencias dadas entre trabajos. En informática, las aplicaciones de este tipo surgen en la programación de instrucciones, el ordenamiento de la evaluación de celdas de fórmulas al volver a calcular los valores de fórmulas en hojas de cálculo, la síntesis lógica, la determinación del orden de las tareas de compilación a realizar en archivos make, la serialización de datos y la resolución de dependencias de símbolos en enlazadores [ 2 ]. 

Artículos relacionados:  
Algoritmo de Kahn para clasificación topológica : otro algoritmo O(V + E). 
Todos los tipos topológicos de un gráfico acíclico dirigido

Referencias:  
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/topoSort.htm  
http://en.wikipedia.org/wiki/Topological_sorting
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *