stringtranslate.com

Búsqueda en profundidad

La búsqueda en profundidad ( DFS ) es un algoritmo para atravesar o buscar estructuras de datos de árboles o gráficos . El algoritmo comienza en el nodo raíz (seleccionando algún nodo arbitrario como nodo raíz en el caso de un gráfico) y explora lo más posible a lo largo de cada rama antes de retroceder. Se necesita memoria adicional, generalmente una pila , para realizar un seguimiento de los nodos descubiertos hasta el momento a lo largo de una rama específica, lo que ayuda a retroceder en el gráfico.

En el siglo XIX, el matemático francés Charles Pierre Trémaux [1] investigó una versión de búsqueda en profundidad como estrategia para resolver laberintos . [2] [3]

Propiedades

El análisis temporal y espacial de DFS difiere según su área de aplicación. En informática teórica, DFS se utiliza normalmente para recorrer un gráfico completo y lleva tiempo , [4] donde es el número de vértices y el número de aristas . Esto es lineal en el tamaño del gráfico. En estas aplicaciones, también utiliza espacio en el peor de los casos para almacenar la pila de vértices en la ruta de búsqueda actual, así como el conjunto de vértices ya visitados. Por lo tanto, en esta configuración, los límites de tiempo y espacio son los mismos que para la búsqueda en amplitud y la elección de cuál de estos dos algoritmos usar depende menos de su complejidad y más de las diferentes propiedades de los ordenamientos de los vértices que producen los dos algoritmos. .

Para aplicaciones de DFS en relación con dominios específicos, como la búsqueda de soluciones en inteligencia artificial o el rastreo web, el gráfico que se debe recorrer suele ser demasiado grande para visitarlo en su totalidad o infinito (DFS puede sufrir de no terminación ). En tales casos, la búsqueda sólo se realiza hasta una profundidad limitada ; Debido a recursos limitados, como memoria o espacio en disco, normalmente no se utilizan estructuras de datos para realizar un seguimiento del conjunto de todos los vértices visitados anteriormente. Cuando la búsqueda se realiza a una profundidad limitada, el tiempo sigue siendo lineal en términos del número de vértices y aristas expandidas (aunque este número no es lo mismo que el tamaño de todo el gráfico porque algunos vértices se pueden buscar más de una vez y otros en absoluto), pero la complejidad espacial de esta variante de DFS es solo proporcional al límite de profundidad y, como resultado, es mucho menor que el espacio necesario para buscar a la misma profundidad usando la búsqueda en amplitud. Para tales aplicaciones, DFS también se presta mucho mejor a los métodos heurísticos para elegir una rama que parezca probable. Cuando no se conoce a priori un límite de profundidad apropiado, la búsqueda iterativa de profundidad primero aplica DFS repetidamente con una secuencia de límites crecientes. En el modo de análisis de inteligencia artificial, con un factor de ramificación mayor que uno, la profundización iterativa aumenta el tiempo de ejecución solo en un factor constante en el caso en que se conoce el límite de profundidad correcto debido al crecimiento geométrico del número de nodos por nivel. .

DFS también se puede utilizar para recopilar una muestra de nodos del gráfico. Sin embargo, la DFS incompleta, al igual que la BFS incompleta , está sesgada hacia nodos de alto grado .

Ejemplo

Ejemplo animado de una búsqueda en profundidad

Para el siguiente gráfico:

Un gráfico no dirigido con aristas AB, BD, BF, FE, AC, CG, AE

una búsqueda en profundidad que comienza en el nodo A, suponiendo que los bordes izquierdos en el gráfico mostrado se eligen antes que los bordes derechos, y suponiendo que la búsqueda recuerda los nodos visitados anteriormente y no los repetirá (ya que este es un gráfico pequeño), visitará los nodos en el siguiente orden: A, B, D, F, E, C, G. Las aristas atravesadas en esta búsqueda forman un árbol de Trémaux , una estructura con importantes aplicaciones en teoría de grafos . Realizar la misma búsqueda sin recordar los nodos visitados anteriormente da como resultado visitar los nodos en el orden A, B, D, F, E, A, B, D, F, E, etc. para siempre, atrapados en A, B, D, Ciclo F, E y nunca llega a C o G.

La profundización iterativa es una técnica para evitar este bucle infinito y llegaría a todos los nodos.

Resultado de una búsqueda en profundidad

Los cuatro tipos de aristas definidas por un árbol de expansión.

El resultado de una búsqueda en profundidad de un gráfico se puede describir convenientemente en términos de un árbol de expansión de los vértices alcanzados durante la búsqueda. Con base en este árbol de expansión, los bordes del gráfico original se pueden dividir en tres clases: bordes delanteros , que apuntan desde un nodo del árbol a uno de sus descendientes, bordes posteriores , que apuntan desde un nodo a uno de sus antepasados, y bordes cruzados , que no hacen ninguna de las dos cosas. A veces, los bordes del árbol , que pertenecen al propio árbol de expansión, se clasifican por separado de los bordes delanteros. Si el gráfico original no está dirigido, entonces todos sus bordes son bordes de árbol o bordes posteriores.

Ordenamiento de vértices

También es posible utilizar la búsqueda en profundidad para ordenar linealmente los vértices de un gráfico o árbol. Hay cuatro formas posibles de hacer esto:

Para los árboles binarios, existe además el ordenamiento inverso y el ordenamiento inverso .

Por ejemplo, cuando se busca el gráfico dirigido a continuación comenzando en el nodo A, la secuencia de recorridos es ABDBACA o ACDCABA (la elección de visitar primero B o C desde A depende del algoritmo). Tenga en cuenta que aquí se incluyen las visitas repetidas en forma de retroceder a un nodo, para comprobar si aún tiene vecinos no visitados (incluso si no tiene ninguno). Por lo tanto, los posibles pedidos previos son ABDC y ACDB, mientras que los posibles pedidos posteriores son DBCA y DCBA, y los posibles pedidos posteriores inversos son ACBD y ABC D.

Un gráfico dirigido con aristas AB, BD, AC, CD

El postordenamiento inverso produce una clasificación topológica de cualquier gráfico acíclico dirigido . Este orden también es útil en el análisis de flujo de control , ya que a menudo representa una linealización natural de los flujos de control. El gráfico anterior podría representar el flujo de control en el fragmento de código siguiente, y es natural considerar este código en el orden ABCD o ACBD, pero no es natural usar el orden ABDC o ACD B.

si ( A ) entonces { B} demás { C}D

Pseudocódigo

Entrada : Salida : Una implementación recursiva de DFS: [5]

El procedimiento DFS( G , v ) es etiqueta v como descubierto para todos los bordes dirigidos de v a w que están  en  G .adjacentEdges( v ) si el vértice w no está etiquetado como descubierto entonces llame recursivamente a DFS( G , w )

Una implementación no recursiva de DFS con la peor complejidad espacial , con la posibilidad de duplicar vértices en la pila: [6]

El procedimiento DFS_iterative( G , v ) es dejar que S sea una pila S .push( v ) mientras que  S no esté vacío do  v = S .pop() si  v no está etiquetado como descubierto, entonces etiquete v como descubierto para todos los bordes desde v hasta w  en  G .adjacentEdges( v ) hacer  S .push( w )
Un gráfico no dirigido con aristas AB, BD, BF, FE, AC, CG, AE
El gráfico de ejemplo, copiado desde arriba.

Estas dos variaciones de DFS visitan a los vecinos de cada vértice en orden opuesto entre sí: el primer vecino de v visitado por la variación recursiva es el primero en la lista de aristas adyacentes, mientras que en la variación iterativa el primer vecino visitado es el último en la lista de bordes adyacentes. La implementación recursiva visitará los nodos del gráfico de ejemplo en el siguiente orden: A, B, D, F, E, C, G. La implementación no recursiva visitará los nodos como: A, E, F, B, D , C, G.

La implementación no recursiva es similar a la búsqueda en amplitud , pero se diferencia de ella en dos formas:

  1. utiliza una pila en lugar de una cola, y
  2. retrasa la verificación de si se ha descubierto un vértice hasta que el vértice se extrae de la pila en lugar de realizar esta verificación antes de agregar el vértice.

Si G es un árbol , reemplazar la cola del algoritmo de búsqueda en amplitud con una pila producirá un algoritmo de búsqueda en profundidad. Para gráficos generales, reemplazar la pila de la implementación iterativa de búsqueda en profundidad con una cola también produciría un algoritmo de búsqueda en amplitud, aunque algo no estándar. [7]

Otra posible implementación de la búsqueda iterativa en profundidad utiliza una pila de iteradores de la lista de vecinos de un nodo, en lugar de una pila de nodos. Esto produce el mismo recorrido que el DFS recursivo. [8]

El procedimiento DFS_iterative ( G , v ) es dejar que S sea una pila. etiqueta v como se descubrió S .push(iterador de G .adjacentEdges( v )) mientras  S no está vacío , hazlo  si  S .peek().hasNext() entonces  w = S .peek().next() si  w no está etiquetado como se descubrió, entonces la etiqueta fue descubierta S .push(iterador de G .adjacentEdges( w )) else  S .pop()

Aplicaciones

Algoritmo aleatorio similar a la búsqueda en profundidad utilizada para generar un laberinto.

Los algoritmos que utilizan la búsqueda en profundidad como componente básico incluyen:

Complejidad

John Reif investigó la complejidad computacional de DFS . Más precisamente, dado un gráfico , sea el orden calculado por el algoritmo DFS recursivo estándar. Este orden se denomina orden lexicográfico de búsqueda en profundidad. John Reif consideró la complejidad de calcular el orden de búsqueda lexicográfica en profundidad, dado un gráfico y una fuente. Una versión de decisión del problema (probar si algún vértice u ocurre antes de algún vértice v en este orden) es P -completa , [12] lo que significa que es "una pesadilla para el procesamiento paralelo ". [13] : 189 

Un orden de búsqueda en profundidad (no necesariamente lexicográfico) puede calcularse mediante un algoritmo paralelo aleatorio en la clase de complejidad RNC . [14] En 1997, aún se desconocía si un recorrido en profundidad podría construirse mediante un algoritmo paralelo determinista, en la clase de complejidad NC . [15]

Ver también

Notas

  1. ^ Charles Pierre Trémaux (1859–1882) École polytechnique of Paris (X:1876), ingeniero francés del telégrafo
    en conferencia pública, 2 de diciembre de 2010 - por el profesor Jean Pelletier-Thibert en la Académie de Macon (Borgoña - Francia) - ( Resumen publicado en Anales Académicos, marzo 2011 – ISSN  0980-6032)
  2. ^ Even, Shimon (2011), Algoritmos gráficos (2ª ed.), Cambridge University Press, págs. 46–48, ISBN 978-0-521-73653-4.
  3. ^ Sedgewick, Robert (2002), Algoritmos en C++: algoritmos gráficos (3.ª ed.), Pearson Education, ISBN 978-0-201-36118-6.
  4. ^ Cormen, Thomas H., Charles E. Leiserson y Ronald L. Rivest. p.606
  5. ^ Goodrich y Tamassia; Cormen, Leiserson, Rivest y Stein
  6. ^ Página 93, Diseño de algoritmos, Kleinberg y Tardos
  7. ^ "Recorrido de gráficos basado en pila ≠ primera búsqueda en profundidad". 11011110.github.io . Consultado el 10 de junio de 2020 .
  8. ^ Sedgewick, Robert (2010). Algoritmos en Java. Addison-Wesley. ISBN 978-0-201-36121-6. OCLC  837386973.
  9. ^ Hopcroft, John ; Tarjan, Robert E. (1974), "Pruebas de planaridad eficiente" (PDF) , Revista de la Asociación de Maquinaria de Computación , 21 (4): 549–568, doi :10.1145/321850.321852, hdl : 1813/6011 , S2CID  6279825.
  10. ^ de Fraysseix, H.; Ossona de Méndez, P .; Rosenstiehl, P. (2006), "Trémaux Trees and Planarity", Revista internacional de fundamentos de la informática , 17 (5): 1017–1030, arXiv : math/0610935 , Bibcode : 2006math..... 10935D, doi : 10.1142/S0129054106004248, S2CID  40107560.
  11. ^ Baccelli, Francois; Haji-Mirsadeghi, Mir-Omid; Khezeli, Ali (2018), "Árboles genealógicos eternos y dinámica en gráficos aleatorios unimodulares", en Sobieczky, Florian (ed.), Unimodularidad en gráficos generados aleatoriamente: sesión especial de AMS, 8 al 9 de octubre de 2016, Denver, Colorado , Contemporáneo Matemáticas, vol. 719, Providence, Rhode Island: Sociedad Matemática Estadounidense, págs. 85–127, arXiv : 1608.05940 , doi : 10.1090/conm/719/14471, MR  3880014, S2CID  119173820; consulte el ejemplo 3.7, pág. 93
  12. ^ Reif, John H. (1985). "La búsqueda en profundidad es inherentemente secuencial". Cartas de procesamiento de información . 20 (5): 229–234. doi :10.1016/0020-0190(85)90024-9.
  13. ^ Mehlhorn, Kurt ; Lijadoras, Peter (2008). Algoritmos y estructuras de datos: la caja de herramientas básica (PDF) . Saltador. Archivado (PDF) desde el original el 8 de septiembre de 2015.
  14. ^ Aggarwal, A.; Anderson, RJ (1988), "Un algoritmo NC aleatorio para búsqueda en profundidad", Combinatorica , 8 (1): 1–12, doi :10.1007/BF02122548, MR  0951989, S2CID  29440871.
  15. ^ Karger, David R .; Motwani, Rajeev (1997), "Un algoritmo NC para cortes mínimos", SIAM Journal on Computing , 26 (1): 255–272, CiteSeerX 10.1.1.33.1701 , doi :10.1137/S0097539794273083, MR  1431256 .

Referencias

enlaces externos