# Dijkstra算法：邻接表表示的算法实现|贪婪算法S8

2021年4月7日18:00:05 发表评论 699 次浏览

## 本文概述

1. 贪婪算法|S7(Dijkstra的最短路径算法)

2. 图及其表示

1)创建大小为V的最小堆, 其中V是给定图中的顶点数。最小堆的每个节点都包含顶点数和顶点的距离值。

2)以源顶点为根初始化Min Heap(分配给源顶点的距离值为0)。分配给所有其他顶点的距离值为INF(无限)。

3)当Min Heap不为空时, 请执行以下操作

…..a)从最小堆中提取具有最小距离值节点的顶点。令提取的顶点为u。

…..b)对于u的每个相邻顶点v, 检查v是否在Min Heap中。如果v在"最小堆"中, 并且距离值大于u-v的权重加上u的距离值, 则更新v的距离值。

Dijkstra的最短路径算法，使用邻接表表示的贪婪算法实现代码如下：

## C ++

``````//C /C++ program for Dijkstra's
//shortest path algorithm for adjacency
//list representation of graph
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

//A structure to represent a
//node in adjacency list
{
int dest;
int weight;
};

//A structure to represent
{

//Pointer to head node of list
};

//A structure to represent a graph.
//A graph is an array of adjacency lists.
//Size of array will be V (number of
//vertices in graph)
struct Graph
{
int V;
};

//A utility function to create
//a new adjacency list node
int dest, int weight)
{
struct AdjListNode* newNode =
malloc ( sizeof ( struct AdjListNode));
newNode->dest = dest;
newNode->weight = weight;
newNode->next = NULL;
return newNode;
}

//A utility function that creates
//a graph of V vertices
struct Graph* createGraph( int V)
{
struct Graph* graph = ( struct Graph*)
malloc ( sizeof ( struct Graph));
graph->V = V;

//Create an array of adjacency lists.
//Size of array will be V
graph->array = ( struct AdjList*)
malloc (V * sizeof ( struct AdjList));

//Initialize each adjacency list
//as empty by making head as NULL
for ( int i = 0; i <V; ++i)

return graph;
}

//Adds an edge to an undirected graph
void addEdge( struct Graph* graph, int src, int dest, int weight)
{
//Add an edge from src to dest.
//A new node is added to the adjacency
//list of src.  The node is
//added at the beginning
struct AdjListNode* newNode =

//Since graph is undirected, //add an edge from dest to src also
newNode = newAdjListNode(src, weight);
}

//Structure to represent a min heap node
struct MinHeapNode
{
int  v;
int dist;
};

//Structure to represent a min heap
struct MinHeap
{

//Number of heap nodes present currently
int size;

//Capacity of min heap
int capacity;

//This is needed for decreaseKey()
int *pos;
struct MinHeapNode **array;
};

//A utility function to create a
//new Min Heap Node
struct MinHeapNode* newMinHeapNode( int v, int dist)
{
struct MinHeapNode* minHeapNode =
( struct MinHeapNode*)
malloc ( sizeof ( struct MinHeapNode));
minHeapNode->v = v;
minHeapNode->dist = dist;
return minHeapNode;
}

//A utility function to create a Min Heap
struct MinHeap* createMinHeap( int capacity)
{
struct MinHeap* minHeap =
( struct MinHeap*)
malloc ( sizeof ( struct MinHeap));
minHeap->pos = ( int *) malloc (
capacity * sizeof ( int ));
minHeap->size = 0;
minHeap->capacity = capacity;
minHeap->array =
( struct MinHeapNode**)
malloc (capacity *
sizeof ( struct MinHeapNode*));
return minHeap;
}

//A utility function to swap two
//nodes of min heap.
//Needed for min heapify
void swapMinHeapNode( struct MinHeapNode** a, struct MinHeapNode** b)
{
struct MinHeapNode* t = *a;
*a = *b;
*b = t;
}

//A standard function to
//heapify at given idx
//This function also updates
//position of nodes when they are swapped.
//Position is needed for decreaseKey()
void minHeapify( struct MinHeap* minHeap, int idx)
{
int smallest, left, right;
smallest = idx;
left = 2 * idx + 1;
right = 2 * idx + 2;

if (left <minHeap->size &&
minHeap->array[left]->dist <
minHeap->array[smallest]->dist )
smallest = left;

if (right <minHeap->size &&
minHeap->array[right]->dist <
minHeap->array[smallest]->dist )
smallest = right;

if (smallest != idx)
{
//The nodes to be swapped in min heap
MinHeapNode *smallestNode =
minHeap->array[smallest];
MinHeapNode *idxNode =
minHeap->array[idx];

//Swap positions
minHeap->pos[smallestNode->v] = idx;
minHeap->pos[idxNode->v] = smallest;

//Swap nodes
swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);

minHeapify(minHeap, smallest);
}
}

//A utility function to check if
//the given minHeap is ampty or not
int isEmpty( struct MinHeap* minHeap)
{
return minHeap->size == 0;
}

//Standard function to extract
//minimum node from heap
struct MinHeapNode* extractMin( struct MinHeap*
minHeap)
{
if (isEmpty(minHeap))
return NULL;

//Store the root node
struct MinHeapNode* root =
minHeap->array[0];

//Replace root node with last node
struct MinHeapNode* lastNode =
minHeap->array[minHeap->size - 1];
minHeap->array[0] = lastNode;

//Update position of last node
minHeap->pos[root->v] = minHeap->size-1;
minHeap->pos[lastNode->v] = 0;

//Reduce heap size and heapify root
--minHeap->size;
minHeapify(minHeap, 0);

return root;
}

//Function to decreasy dist value
//of a given vertex v. This function
//uses pos[] of min heap to get the
//current index of node in min heap
void decreaseKey( struct MinHeap* minHeap, int v, int dist)
{
//Get the index of v in  heap array
int i = minHeap->pos[v];

//Get the node and update its dist value
minHeap->array[i]->dist = dist;

//Travel up while the complete
//tree is not hepified.
//This is a O(Logn) loop
while (i && minHeap->array[i]->dist <
minHeap->array[(i - 1) /2]->dist)
{
//Swap this node with its parent
minHeap->pos[minHeap->array[i]->v] =
(i-1)/2;
minHeap->pos[minHeap->array[
(i-1)/2]->v] = i;
swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) /2]);

//move to parent index
i = (i - 1) /2;
}
}

//A utility function to check if a given vertex
//'v' is in min heap or not
bool isInMinHeap( struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] <minHeap->size)
return true ;
return false ;
}

//A utility function used to print the solution
void printArr( int dist[], int n)
{
printf ( "Vertex   Distance from Source\n" );
for ( int i = 0; i <n; ++i)
printf ( "%d \t\t %d\n" , i, dist[i]);
}

//The main function that calulates
//distances of shortest paths from src to all
//vertices. It is a O(ELogV) function
void dijkstra( struct Graph* graph, int src)
{

//Get the number of vertices in graph
int V = graph->V;

//dist values used to pick
//minimum weight edge in cut
int dist[V];

//minHeap represents set E
struct MinHeap* minHeap = createMinHeap(V);

//Initialize min heap with all
//vertices. dist value of all vertices
for ( int v = 0; v <V; ++v)
{
dist[v] = INT_MAX;
minHeap->array[v] = newMinHeapNode(v, dist[v]);
minHeap->pos[v] = v;
}

//Make dist value of src vertex
//as 0 so that it is extracted first
minHeap->array[src] =
newMinHeapNode(src, dist[src]);
minHeap->pos[src]   = src;
dist[src] = 0;
decreaseKey(minHeap, src, dist[src]);

//Initially size of min heap is equal to V
minHeap->size = V;

//In the followin loop, //min heap contains all nodes
//whose shortest distance
//is not yet finalized.
while (!isEmpty(minHeap))
{
//Extract the vertex with
//minimum distance value
struct MinHeapNode* minHeapNode =
extractMin(minHeap);

//Store the extracted vertex number
int u = minHeapNode->v;

//Traverse through all adjacent
//vertices of u (the extracted
//vertex) and update
//their distance values
struct AdjListNode* pCrawl =
while (pCrawl != NULL)
{
int v = pCrawl->dest;

//If shortest distance to v is
//not finalized yet, and distance to v
//through u is less than its
//previously calculated distance
if (isInMinHeap(minHeap, v) &&
dist[u] != INT_MAX &&
pCrawl->weight + dist[u] <dist[v])
{
dist[v] = dist[u] + pCrawl->weight;

//update distance
//value in min heap also
decreaseKey(minHeap, v, dist[v]);
}
pCrawl = pCrawl->next;
}
}

//print the calculated shortest distances
printArr(dist, V);
}

//Driver program to test above functions
int main()
{
//create the graph given in above fugure
int V = 9;
struct Graph* graph = createGraph(V);
addEdge(graph, 0, 1, 4);
addEdge(graph, 0, 7, 8);
addEdge(graph, 1, 2, 8);
addEdge(graph, 1, 7, 11);
addEdge(graph, 2, 3, 7);
addEdge(graph, 2, 8, 2);
addEdge(graph, 2, 5, 4);
addEdge(graph, 3, 4, 9);
addEdge(graph, 3, 5, 14);
addEdge(graph, 4, 5, 10);
addEdge(graph, 5, 6, 2);
addEdge(graph, 6, 7, 1);
addEdge(graph, 6, 8, 6);
addEdge(graph, 7, 8, 7);

dijkstra(graph, 0);

return 0;
}``````

## python

``````# A Python program for Dijkstra's shortest
# path algorithm for adjacency
# list representation of graph

from collections import defaultdict
import sys

class Heap():

def __init__( self ):
self .array = []
self .size = 0
self .pos = []

def newMinHeapNode( self , v, dist):
minHeapNode = [v, dist]
return minHeapNode

# A utility function to swap two nodes
# of min heap. Needed for min heapify
def swapMinHeapNode( self , a, b):
t = self .array[a]
self .array[a] = self .array[b]
self .array[b] = t

# A standard function to heapify at given idx
# This function also updates position of nodes
# when they are swapped.Position is needed
# for decreaseKey()
def minHeapify( self , idx):
smallest = idx
left = 2 * idx + 1
right = 2 * idx + 2

if left <self .size and
self .array[left][ 1 ] \
<self .array[smallest][ 1 ]:
smallest = left

if right <self .size and
self .array[right][ 1 ]\
<self .array[smallest][ 1 ]:
smallest = right

# The nodes to be swapped in min
# heap if idx is not smallest
if smallest ! = idx:

# Swap positions
self .pos[ self .array[smallest][ 0 ]]
= idx
self .pos[ self .array[idx][ 0 ]] =
smallest

# Swap nodes
self .swapMinHeapNode(smallest, idx)

self .minHeapify(smallest)

# Standard function to extract minimum
# node from heap
def extractMin( self ):

# Return NULL wif heap is empty
if self .isEmpty() = = True :
return

# Store the root node
root = self .array[ 0 ]

# Replace root node with last node
lastNode = self .array[ self .size - 1 ]
self .array[ 0 ] = lastNode

# Update position of last node
self .pos[lastNode[ 0 ]] = 0
self .pos[root[ 0 ]] = self .size - 1

# Reduce heap size and heapify root
self .size - = 1
self .minHeapify( 0 )

return root

def isEmpty( self ):
return True if self .size = = 0 else False

def decreaseKey( self , v, dist):

# Get the index of v in  heap array

i = self .pos[v]

# Get the node and update its dist value
self .array[i][ 1 ] = dist

# Travel up while the complete tree is
# not hepified. This is a O(Logn) loop
while i> 0 and self .array[i][ 1 ] <
self .array[(i - 1 ) /2 ][ 1 ]:

# Swap this node with its parent
self .pos[ self .array[i][ 0 ] ] = (i - 1 ) /2
self .pos[ self .array[(i - 1 ) /2 ][ 0 ] ] = i
self .swapMinHeapNode(i, (i - 1 ) /2 )

# move to parent index
i = (i - 1 ) /2 ;

# A utility function to check if a given
# vertex 'v' is in min heap or not
def isInMinHeap( self , v):

if self .pos[v] <self .size:
return True
return False

def printArr(dist, n):
print "Vertex\tDistance from source"
for i in range (n):
print "%d\t\t%d" % (i, dist[i])

class Graph():

def __init__( self , V):
self .V = V
self .graph = defaultdict( list )

# Adds an edge to an undirected graph
def addEdge( self , src, dest, weight):

# Add an edge from src to dest.  A new node
# is added to the adjacency list of src. The
# node is added at the beginning. The first
# element of the node has the destination
# and the second elements has the weight
newNode = [dest, weight]
self .graph[src].insert( 0 , newNode)

# Since graph is undirected, add an edge
# from dest to src also
newNode = [src, weight]
self .graph[dest].insert( 0 , newNode)

# The main function that calulates distances
# of shortest paths from src to all vertices.
# It is a O(ELogV) function
def dijkstra( self , src):

V = self .V  # Get the number of vertices in graph
dist = []   # dist values used to pick minimum
# weight edge in cut

# minHeap represents set E
minHeap = Heap()

#  Initialize min heap with all vertices.
# dist value of all vertices
for v in range (V):
dist.append(sys.maxint)
minHeap.array.append( minHeap.
newMinHeapNode(v, dist[v]))
minHeap.pos.append(v)

# Make dist value of src vertex as 0 so
# that it is extracted first
minHeap.pos[src] = src
dist[src] = 0
minHeap.decreaseKey(src, dist[src])

# Initially size of min heap is equal to V
minHeap.size = V;

# In the following loop, # min heap contains all nodes
# whose shortest distance is not yet finalized.
while minHeap.isEmpty() = = False :

# Extract the vertex
# with minimum distance value
newHeapNode = minHeap.extractMin()
u = newHeapNode[ 0 ]

# Traverse through all adjacent vertices of
# u (the extracted vertex) and update their
# distance values
for pCrawl in self .graph[u]:

v = pCrawl[ 0 ]

# If shortest distance to v is not finalized
# yet, and distance to v through u is less
# than its previously calculated distance
if minHeap.isInMinHeap(v) and
dist[u] ! = sys.maxint and \
pCrawl[ 1 ] + dist[u] <dist[v]:
dist[v] = pCrawl[ 1 ] + dist[u]

# update distance value
# in min heap also
minHeap.decreaseKey(v, dist[v])

printArr(dist, V)

# Driver program to test the above functions
graph = Graph( 9 )
graph.addEdge( 0 , 1 , 4 )
graph.addEdge( 0 , 7 , 8 )
graph.addEdge( 1 , 2 , 8 )
graph.addEdge( 1 , 7 , 11 )
graph.addEdge( 2 , 3 , 7 )
graph.addEdge( 2 , 8 , 2 )
graph.addEdge( 2 , 5 , 4 )
graph.addEdge( 3 , 4 , 9 )
graph.addEdge( 3 , 5 , 14 )
graph.addEdge( 4 , 5 , 10 )
graph.addEdge( 5 , 6 , 2 )
graph.addEdge( 6 , 7 , 1 )
graph.addEdge( 6 , 8 , 6 )
graph.addEdge( 7 , 8 , 7 )
graph.dijkstra( 0 )

# This code is contributed by Divyanshu Mehta``````

``````Vertex   Distance from Source
0                0
1                4
2                12
3                19
4                21
5                11
6                9
7                8
8                14``````

Dijkstra算法时间复杂度：上面的代码/算法的时间复杂度看起来是O(V ^ 2), 因为有两个嵌套的while循环。如果仔细观察, 可以观察到内部循环中的语句执行了O(V + E)次(类似于BFS)。内部循环具有reduceKey()操作, 该操作需要O(LogV)时间。因此, 总体时间复杂度为O(E + V)* O(LogV), 即O((E + V)* LogV)= O(ELogV)

Dijkstra的最短路径算法笔记：

1. 该代码计算最短距离, 但不计算路径信息。我们可以创建一个父数组, 在距离更新时更新父数组(例如总理的实施), 并使用它显示从源到不同顶点的最短路径。
2. 该代码用于无向图, 相同的dijekstra函数也可用于有向图。
3. 该代码查找从源到所有顶点的最短距离。如果我们在最短的距离只关心从源到单个目标, 我们可以break for循环时所拾取最小距离顶点等于目标(算法的步骤3.A)。
4. Dijkstra算法不适用于负边缘为负的图表。对于负负边的图形, Bellman–Ford算法可以使用, 我们将在单独的文章中进行讨论。
Dijkstra最短路径算法中的打印路径
Dijkstra使用STL中的集合的最短路径算法

Clifford Stein, Thomas H.Cormen, Charles E.Leiserson, Ronald L.

Sanjoy Dasgupta, Christos Papadimitriou, Umesh Vazirani的算法