La complejidad del tiempo del algoritmo de Dijkstra

La complejidad del tiempo del algoritmo de Dijkstra
"El algoritmo de Dijkstra busca la ruta más corta entre dos nodos en un gráfico. El nodo también se llama vértice en obras gráficas. Una rama en un gráfico también se llama borde. Para simplificar, el programa en este artículo buscará la ruta más corta entre un vértice de origen y un vértice de destino."

Considere las siguientes ciudades: A, B, C, D, E y F conectadas por carreteras:

Estas ciudades están conectadas por carreteras (que se puede suponer que son rectas). La carretera de la ciudad A a la ciudad B es de 4 unidades; no se dibuja a la escala. La carretera de la ciudad a a la ciudad C es de 5 unidades; no se dibuja a la escala. La duración de la ciudad B a la ciudad es de 11 unidades, no atraídos a la escala. Las carreteras entre otras ciudades están indicadas de manera similar.

Las ciudades: A, B, C, D, E y F son los vértices de un gráfico. Las carreteras son los bordes del gráfico. Sin embargo, este gráfico se representará en una estructura de datos matemáticos, de manera diferente a su diseño geográfico.

El algoritmo de Dijkstra se puede usar para encontrar la ruta más corta entre un vértice de origen (digamos a) y cualquier otro vértice. Para una simplicidad adicional, este artículo tendrá como objetivo buscar el camino más corto de A a E E.

Hay diferentes caminos de A a E, con diferentes longitudes, como sigue:

A-B-D-F: 4 + 9 + 2 = 15
A-B-E-F: 4 + 7 + 6 = 17
A-B-C-E-F: 4 + 11 + 3 + 6 = 24
A-B-C-E-D-F: 4 + 11 + 3 + 13 + 2 = 33
A-B-D-E-F: 4 + 9 + 13 + 6 = 32
A-B-E-D-F: 4 + 7 + 13 + 2 = 26
A-C-E-F: 5 + 3 + 6 = 14
A-C-B-D-F: 5 + 11 + 9 + 2 = 27
A-C-B-E-F: 5 + 11 + 7 + 6 = 29
A-C-B-E-F: 5 + 11 + 7 + 6 = 29
A-C-E-D-F: 5 + 3 + 13 + 2 = 14
A-C-B-E-D-F: 5 + 11 + 7 + 13 + 2 = 38

De esta lista, la ruta más corta es A-C-E-F, con una longitud total de 14 unidades.

El objetivo principal de este artículo es encontrar el tiempo de ejecución que se necesita el algoritmo de Dijkstra para obtener el camino más corto de A a E. El tiempo no se dará en segundos o minutos. Es el tiempo de ejecución total relativo, llamado complejidad del tiempo, lo que se dará. La codificación de C ++ también se proporciona.

Gráfico para usar

La complejidad del tiempo (tiempo de ejecución relativo) depende principalmente del tipo de gráfico matemático utilizado para representar el diseño geográfico. También depende del algoritmo (otro tipo de algoritmo) utilizado para ordenar los vértices vecinos de cada vértice en el algoritmo general (algoritmo de Dijkstra). La clasificación de vértices vecinos no se aborda en este artículo.

El gráfico matemático elegido para este artículo se llama Matriz de adyacencia. Es:

Los encabezados de la fila son los nombres de la ciudad de A a F. Los encabezados de la columna son los mismos nombres de la ciudad de A a F. Cada entrada es la duración de una carretera de una ciudad a la siguiente. La duración de un camino de una ciudad a sí misma es cero. La duración de una carretera de una ciudad a otra, después de omitir una o más ciudades, también es cero. Solo se consideran caminos directos. Cada entrada se encuentra, primero por fila y luego por columna. Una vez más, cada entrada es la duración de una carretera, sin omitir una ciudad, y no a la ciudad misma. Esta matriz es una representación matemática de la red geográfica dada anteriormente.

Entonces, la matriz consta de bordes, con los encabezados de fila y columna de los mismos vértices. La matriz es la estructura principal necesaria en el programa. Se utilizan otros dos vectores (matrices) en este programa básico.

Algoritmo de Dijkstra

El algoritmo de Dijkstra busca la ruta más corta entre dos vértices en un gráfico (red). La matriz anterior es el gráfico, que corresponde a la red geográfica anterior. Para simplificar, el programa en este artículo buscará la ruta más corta entre un vértice de origen y un vértice de destino. Precisamente, el programa buscará la ruta más corta desde el vértice de origen, a, hasta el vértice de destino, F.

El algoritmo, como relevante para esta tarea, es el siguiente:

- Todos los vértices están marcados como no visitados. En este punto, se crean un conjunto de todos los vértices no visitados.

- Asigne un valor de longitud de ruta tentativa a todos los vértices: la longitud de ruta desde la fuente a la fuente se le asigna un valor de cero; La longitud de la ruta de la fuente a cualquier otro vértice se le asigna el valor único del infinito, i.mi., un valor que es más alto que la ruta más alta posible, en el gráfico. El valor de cada vértice cambiaría al menos una vez, de un valor alto a un valor más bajo, a medida que continúa el algoritmo. Se centrarán los posibles vértices para la ruta más corta completa, comenzando desde el vértice de origen (a). El vértice con el enfoque se llama vértice actual. El vértice actual tiene vecinos, mejor visualizados de la red real (diseño geográfico) arriba.

- Existe el vértice actual, y está el vértice visitado. De hecho, habría más de un vértice visitado en una cadena a medida que el algoritmo continúa. Todos los vértices anteriores considerados visitados están en la ruta completa más corta que se está desarrollando, comenzando desde la fuente. Se conoce la longitud de la ruta del último vértice visitado (debe ser conocido). Se declara un vértice visitado cuando se confirma la longitud de su ruta. El vértice visitado da la menor longitud de ruta de la fuente hasta ahora, ya que el algoritmo está en progreso. Los vecinos no visitados del vértice actual, excepto su vecino visitado previo inmediato, tienen valores tentativos (longitudes de ruta de la fuente), algunos de los cuales aún pueden ser infinitos (valor muy alto). Para cada vecino no visitado y el vértice actual, se calcula una nueva longitud de ruta tentativa de la siguiente manera: la longitud de la ruta del vértice visitado previamente, más la longitud del borde al vértice actual, más la longitud del borde del vértice actual, al vértice actual, al vecino no visitado. Si este resultado es menor de lo que había allí, ya que la longitud de la ruta tentativa desde la fuente al vecino no visitado del vértice actual, entonces este valor calculado se convierte en el nuevo valor tentativo para el vecino del vértice actual. Es decir, el nuevo valor de ruta tentativa para un vértice no visitado se calcula a través del vértice actual del vértice visitado previamente.

- Puede haber más de un vértices actuales. Cuando se ha accedido a todos los vecinos de cada vértice actual y se les ha dado nuevas longitudes de ruta tentativa apropiadas, el vértice actual con la menor longitud de ruta de la fuente (menor valor) se considera visitado. Dado que tenía el menor valor, su menor valor se confirma como la longitud más corta de la parrilla hasta ahora. El vértice visitado previamente se elimina del conjunto de vértices no visitado. Un vértice visitado nunca volverá a verificar. Cualquier visita después tendría una mayor longitud del camino.

- Los dos pasos anteriores se repiten, en orden, para cualquier vértice actual que se convierta en un vértice visitado. Esta repetición continúa hasta que se alcanza el vértice de destino. El vértice de destino puede ser cualquier vértice después del vértice de origen. Sin embargo, por simplicidad, el último vértice, F de la red anterior, se ha elegido como el vértice de destino para este artículo.

- A medida que avanza el algoritmo, cada vértice padre (visitado previamente), y cada vértice (a continuación) de niño, de la ruta más corta, se debe registrar en caso de que la ruta más corta, por los vértices, así como la ruta más corta por longitud, se requiere ( pidió). Cuando se alcanza y visita el vértice de destino, la ruta más corta completa se puede rastrear hacia atrás si se necesita la ruta por vértices. En cuanto a la longitud de la ruta, se calculó a medida que avanzaba el algoritmo.

Ilustración Algoritmo de Dijkstra

El camino anterior

La red se utiliza para ilustrar el algoritmo de Dijkstra. Se vuelve a mostrar a continuación para una referencia fácil.

Comienza en la fuente, "A" con una longitud de ruta de cero. "A" se considera visitado y eliminado de la lista no visitada (SET). "A" se envía a una lista visitada en caso de que se requiera la ruta por vértices.

Las longitudes de la ruta de A a B son:

A-B = 4
A-C-B = 5 + 11 = 16

Entre 4, 16 e Infinity (que estaba allí), 4 es el menos. Entonces, B tiene el valor tentativo de 4 como longitud de ruta.

Las longitudes de la ruta de A a C son:

A-C = 5
A-B-C = 4 + 11 = 15

Entre 5, 15 e Infinity (que estaba allí), 5 es el menor. Entonces, C tiene el valor tentativo de 5 como longitud de ruta.

B y C fueron los vecinos no visitados de un. Actualmente, cada uno tiene una longitud de ruta tentativa. Entre B y C, se debe elegir un vértice que contribuyan a la ruta general final. B y C también tienen vecinos.

Los vecinos no visitados de B son D, E y C, con longitudes infinitas tentativas. Los vecinos no visitados de C son B y E con longitudes infinitas tentativas. Un vecino tiene un borde directo del vértice en cuestión.

La longitud de la ruta calculada de A a D, a B es:

A-B-D = 4 + 9 = 13

La longitud de la ruta calculada de A a E, a B es:

A-B-E = 4 + 7 = 11

La longitud de la ruta calculada de A a C, a B es:

A-B-C = 4 + 11 = 15

Esas son las longitudes de camino a través de los vecinos de B a B, del vértice visitado, "A". Las longitudes de la ruta tentativa a través de C también deben determinarse.

La longitud de la ruta calculada desde A a B, a C es:

A-C-B = 5 + 11 = 16

La longitud de la ruta calculada de A a E a C es:

A-C-E = 5 + 3 = 8

Esas son las longitudes de camino a través de los vecinos de C a C, desde el vértice visitado, "A".

Todas las longitudes tentativas calculadas en la ruta parcial hasta ahora son:

A-B-D = 4 + 9 = 13
A-B-E = 4 + 7 = 11
A-B-C = 4 + 11 = 15
A-C-B = 5 + 11 = 16
A-C-E = 5 + 3 = 8

La más corta de estas longitudes parcialas es:

A-C-E = 5 + 3 = 8

Entonces el vértice, C, se elige para el camino a seguir. Este es el próximo vértice visitado. Cualquier camino posible a través de B está abandonado. C se considera luego visitado. El vértice C se elimina de la lista no visitada. C se envía a la lista visitada (para ser después de a).

C debe tener vecinos no visitados con longitudes de ruta tentativa. En este caso, es B y E. B tiene vecinos con longitudes de camino infinitas, que son D y E. E tiene vecinos con longitudes de camino infinitas, que son D y F. Para elegir el siguiente nodo visitado, las longitudes de discusión tentativa de C a B y E deben calcularse. Los cálculos son:

A-C-B-D = 5 + 11 + 9
= 16 + 9 = 25
A-C-B-E = 5 + 11 + 7
= 16 + 7 = 23
A-C-E-D = 5 + 3 + 13
= 8 + 13 = 21
A-C-E-F = 5 + 3 + 6
= 8 + 6 = 14

Lo más corto para estos camisetas parcial es:

A-C-E-F = 8 + 6 = 14

En este punto, E es el camino a seguir. Este es el próximo vértice visitado. Cualquier camino posible a través de D se abandona. E se elimina de la lista no visitada y se agrega a la lista visitada (para ser después de c).

E tiene vecinos no visitados con longitudes de ruta tentativa. En este caso, es D y F. Si F tuviera vecinos no visitados, las longitudes de su camino tentativo de "A", la fuente, debería haber sido infinito. Ahora, la longitud de f a nada es 0. Para elegir el siguiente nodo visitado (vértice), las longitudes de discusión tentativa desde E a D y E a F deben calcularse. Los cálculos son:

A-C-E-D-F = 5 + 3 + 13 + 2
= 8 + 15 = 23
A-C-E-F- = 5 + 3 + 6 + 0
= 14 + 0 = 14

La más corta de estas longitudes parcialas es:

A-C-E-F- = 14

En este punto, F es el camino a seguir. Se considera visitado. F se elimina de la lista no visitada y se agrega a la lista visitada (para ser después de E).

F es el destino. Y así, la longitud de la ruta más corta desde la fuente, A, hasta el destino, F, es 14. Los vértices y su pedido en la lista visitada deben ser A-C-E-F. Esta es la ruta más corta del avance de los vértices. Para obtener la ruta más corta inversa por vértices, lea la lista hacia atrás.

Codificación de C ++

La gráfica

El gráfico para la red es una matriz bidimensional. Es:

int g [v] [v] = 0,4,5,0,0,0,
4,0,11,9,7,0,
5,11,0,0,3,0,
0,9,0,0,13,2,
0,7,3,13,0,6,
0,0,0,2,6,0;

Debe codificarse en la función principal de C ++. Cada entrada es la longitud del borde de un vértice, lectura por filas, al siguiente vértice, lectura por columnas. Tal valor no es para más de un par de vértices.

Vértices como números

Por conveniencia, los vértices serán identificados por números, utilizando la codificación ASCII, de la siguiente manera:

A es 65
B es 66
C es 67
D es 68
E es 69
F es 70
A es 0 + 65 = 65
B es 1 + 65 = 65
C es 2 + 65 = 65
D es 3 + 65 = 65
E es 4 + 65 = 65
F es 5 + 65 = 65

Los valores de codificación para A, B, C, D, E y F son los siguientes:

A = 0
B = 1
C = 2
D = 3
E = 4
F = 5

65 se agregará a cada uno de estos números para obtener el número ASCII correspondiente, del cual se obtendrá la letra correspondiente.

Comienzo del programa

El comienzo del programa es:

#incluir
#incluir
usando el espacio de nombres STD;
int_max = +2'147'483'647; //infinidad
#define v 6 // número de vértice en g
int shortestLength = int_max;
vector sin visitado = 0, 1, 2, 3, 4, 5;
vector visitado;

El valor para el infinito elegido por el programador es 2147483647. El número de vértices, V (en mayúsculas), se define (asignado) como 6. Los elementos del vector no visitado (matriz) son A, B, C, D, E y F, como 0, 1, 2, 3, 4, 5, correspondientes a los números de código ASCII 65, 66, 67, 68, 69, 70. Esta orden, en este caso, no es necesariamente un orden predeterminado y ordenado. Los vértices visitados serán empujados al vector visitado en el orden descubierto por el algoritmo, comenzando con el vértice de la fuente.

La función getNeighBors ()

Esta función obtiene todos los vecinos por delante de un vértice, comenzando justo después del vértice relacionado con la visita previamente visitada. El código de función es:

vectorgetNeighBors (int gráfico [v] [v], int vindx, int prevvisitedIndx)
Vectorneighbors;
para (int j = previsitedIndx+1; jif (gráfico [Vindx] [J] != 0)
vecinos.push_back (j);

Vecinos de regreso;

La función Dijkstra ()

Después de haber sido considerado por el programa del índice de origen (vértice), la función Dijkstra () entra en acción de manera recursiva hasta que se considera el índice de destino (vértice). El código de función es:

void dijkstra (int gráfico [v] [v], int visitedidx, int visitlength)
int visitedIndx = visitedIdx;
int newVisitedIndx = V;
int minLength = int_max;
int visitedlength;
int tentLength1 = 0;
vectorVisitedNbs = getNeighBors (gráfico, visitedIndx, visitedIdx);
para (int i = 0; itentLength1 = VisitLength + Graph [VisitedIdx] [VisitedNbs [i]];
vectorCurrentNbs = getNeighBors (gráfico, visitednbs [i], visitedidx);
if (CurrentNbs.tamaño() != 0)
para (int j = 0; j int tentLength2 = tentLength1 + Graph [VisitedNbs [i]] [CurrentNbs [j]];
if (tentLength2 VisitedLength = tentLength1; // Confirmado, si termina hasta menos
newVisitedIndx = visitednbs [i];



demás
VisitedLength = tentLength1; //confirmado
newVisitedIndx = visitednbs [i];


visitedIndx = newVisitedIndx;
no visitado [visitedIndx] = -1;
visitado.push_back (visitedIndx);
ShortestLength = VisitedLength;
Si (VisitedIndx< V -1)
Dijkstra (gráfico, VisitedIndx, VisitedLength);

La función startdijkstra ()

El algoritmo de Dijkstra comienza con esta función para manejar la situación del código fuente. El código de función es:

void startDijkstra (int gráfico [v] [v], int srcvidx)
int visitedindx = srcvidx;
no visitado [visitedIndx] = -1;
visitado.push_back (visitedIndx);
int visitedLength = 0;
Dijkstra (gráfico, VisitedIndx, VisitedLength);

Los segmentos de código anteriores se pueden ensamblar en el orden otorgado para formar el programa.

La función principal de C ++

Una función principal de C ++ adecuada es:

int main (int argc, char ** argv)

int g [v] [v] = 0,4,5,0,0,0,
4,0,11,9,7,0,
5,11,0,0,3,0,
0,9,0,0,13,2,
0,7,3,13,0,6,
0,0,0,2,6,0;
int Sourcevertex = 0;
startDijkstra (g, fuentevertex);
cout<para (int i = 0; icout<< (char)(visited[i] + 65) << ";
cout<regresar 0;

Conclusión

La complejidad del tiempo es el tiempo de ejecución relativo. Suponiendo que la clasificación de los vértices (vecinos) es buena, se dice que el programa anterior tiene la siguiente complejidad del tiempo:

O ((| E | + | V |) Log | V |)

donde | e | es el número de bordes, | V | es el número de vértices, y un registro es log2. El Big-O con sus soportes, () es una forma de indicar que la expresión en el paréntesis es la complejidad del tiempo (tiempo de ejecución relativo).

La peor complejidad del tiempo para el algoritmo de Dijkstra es: O (| V |2)
[/cc]