Dijkstra算法和Prim算法非常相似(参照链接:C语言 Prim算法和Kruskal算法的实现和证明)
从上面可以看出,Dijkstra算法只是比Prim算法多增加了一个在之后重新计算距离的步骤而已。总的过程:
核心代码:
void changeWeight(AdjGraphPtr adj, int *distTo, int pos) {
EdgePtr tmp = adj->vertexList[pos]->firstEdge;
while (tmp != NULL) {
VTYPE to = getVertexPos(adj, tmp->w);
if (distTo[to] != INFINITE) {
tmp = tmp->next;
continue;
}
tmp->weight = tmp->weight + distTo[pos];
tmp = tmp->next;
}
}
void insertEdgeToQueue(AdjGraphPtr spt, QueuePtr minPQ, EdgePtr edge) {
VTYPE a = edge->v;
VTYPE b = edge->w;
int weight = edge->weight;
int pos_a = getVertexPos(spt, a);
EdgePtr tmp = spt->vertexList[pos_a]->firstEdge;
while (tmp != NULL) {
if (edge->v == tmp->v && edge->w == tmp->w) {
return;
}
if (edge->w == tmp->v && edge->v == tmp->w) {
return;
}
tmp = tmp->next;
}
insertQueue(minPQ, edge, 1);
}
BOOLEAN isMarkedAll(int *distTo, int length) {
for (int i = 0; i < length; i++) {
if (distTo[i] == INFINITE) {
return FALSE;
}
}
return TRUE;
}
void dijkstraSPT(AdjGraphPtr adj) {
/**********初始化********/
QueuePtr minPQ = createQueue(); //保存横截边
AdjGraphPtr spt = (AdjGraphPtr)malloc(sizeof(AdjGraph)); //保存路径
memset(spt, 0, sizeof(AdjGraph));
for (int i = 0; i < adj->vNum; i++) {
insertVertex(spt, adj->vertexList[i]->v);
}
spt->vNum = adj->vNum;
int distTo[6]; //保存距离,标记顶点
for (int i = 0; i < 6; i++) {
distTo[i] = INFINITE;
}
/**********初始化********/
EdgePtr tmp = adj->vertexList[0]->firstEdge;
while(tmp != NULL) {
insertQueue(minPQ, tmp, 1);
tmp = tmp->next;
}
distTo[0] = 0;
while (isQueueEmpty(minPQ) == FALSE && isMarkedAll(distTo, 6)==FALSE) {
EdgePtr minEdge = outQueue(minPQ);
VTYPE from = minEdge->v;
VTYPE to = minEdge->w;
int weight = minEdge->weight;
int toPos = getVertexPos(adj, to);
distTo[toPos] = weight;
insertEdge(spt, from, to, weight);
insertEdge(spt, to, from, weight);
changeWeight(adj, distTo, toPos);
EdgePtr tmp = adj->vertexList[toPos]->firstEdge;
while (tmp != NULL) {
insertEdgeToQueue(spt, minPQ, tmp);
tmp = tmp->next;
}
}
deleteQueue(minPQ);
freeAdj(spt);
}
#include
#include
#include
#include
#define MAXVEX 100
#define MAXNUM 10
#define INFINITE 65525
#define VTYPE char
#define QUETYPE EdgePtr
#define SORTTYPE int
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
typedef struct EdgeNode {
VTYPE v;
VTYPE w;
int weight;
struct EdgeNode *next;
} Edge, *EdgePtr;
typedef struct VertexNode {
VTYPE v;
EdgePtr firstEdge;
} Vertex, *VertexPtr;
typedef struct {
VertexPtr vertexList[MAXVEX];
int vNum;
int eNum;
} AdjGraph, *AdjGraphPtr;
void freeAdj(AdjGraphPtr a);
EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight);
int getVertexPos(const AdjGraphPtr m, const VTYPE key);
void insertVertex(AdjGraphPtr adj, const VTYPE key);
void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight);
AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2);
void print(int *a, int length);
typedef struct node {
QUETYPE data;
struct node *next;
} QueueNode, *QueueNodePtr;
typedef struct {
QueueNodePtr head;
QueueNodePtr tail;
int size;
} Queue, *QueuePtr;
QueuePtr createQueue();
QueueNodePtr createQueueNode(QUETYPE key);
void insertQueue(QueuePtr q, QUETYPE key, int isSort);
QUETYPE outQueue(QueuePtr q);
void deleteQueue(QueuePtr q);
int isQueueEmpty(QueuePtr q);
/**********队列排序**********/
SORTTYPE sortData(QueueNodePtr q) {
return q->data->weight;
}
void exchange(QueueNodePtr a, QueueNodePtr b) {
SORTTYPE *a1 = &(a->data->weight);
SORTTYPE tmp_a = a->data->weight;
SORTTYPE *b1 = &(b->data->weight);
*a1 = b->data->weight;
*b1 = tmp_a;
VTYPE *a2 = &(a->data->v);
VTYPE tmp_a2 = a->data->v;
VTYPE *b2 = &(b->data->v);
*a2 = b->data->v;
*b2 = tmp_a2;
VTYPE *a3 = &(a->data->w);
VTYPE tmp_a3 = a->data->w;
VTYPE *b3 = &(b->data->w);
*a3 = b->data->w;
*b3 = tmp_a3;
}
void queueSort(QueuePtr q) {
//选择排序
QueueNodePtr tmp = NULL;
tmp = q->head;
while (tmp != NULL) {
QueueNodePtr tmp2 = tmp;
SORTTYPE data = sortData(tmp);
while (tmp2 != NULL) {
if (sortData(tmp2) < data) {
exchange(tmp, tmp2);
}
tmp2 = tmp2->next;
}
tmp = tmp->next;
}
}
/**********队列排序**********/
void changeWeight(AdjGraphPtr adj, int *distTo, int pos) {
EdgePtr tmp = adj->vertexList[pos]->firstEdge;
while (tmp != NULL) {
VTYPE to = getVertexPos(adj, tmp->w);
if (distTo[to] != INFINITE) {
tmp = tmp->next;
continue;
}
tmp->weight = tmp->weight + distTo[pos];
tmp = tmp->next;
}
}
void insertEdgeToQueue(AdjGraphPtr spt, QueuePtr minPQ, EdgePtr edge) {
VTYPE a = edge->v;
VTYPE b = edge->w;
int weight = edge->weight;
int pos_a = getVertexPos(spt, a);
EdgePtr tmp = spt->vertexList[pos_a]->firstEdge;
while (tmp != NULL) {
if (edge->v == tmp->v && edge->w == tmp->w) {
return;
}
if (edge->w == tmp->v && edge->v == tmp->w) {
return;
}
tmp = tmp->next;
}
insertQueue(minPQ, edge, 1);
}
BOOLEAN isMarkedAll(int *distTo, int length) {
for (int i = 0; i < length; i++) {
if (distTo[i] == INFINITE) {
return FALSE;
}
}
return TRUE;
}
void dijkstraSPT(AdjGraphPtr adj) {
/**********初始化********/
QueuePtr minPQ = createQueue(); //保存横截边
AdjGraphPtr spt = (AdjGraphPtr)malloc(sizeof(AdjGraph)); //保存路径
memset(spt, 0, sizeof(AdjGraph));
for (int i = 0; i < adj->vNum; i++) {
insertVertex(spt, adj->vertexList[i]->v);
}
spt->vNum = adj->vNum;
int distTo[6]; //保存距离,标记顶点
for (int i = 0; i < 6; i++) {
distTo[i] = INFINITE;
}
/**********初始化********/
EdgePtr tmp = adj->vertexList[0]->firstEdge;
while (tmp != NULL) {
insertQueue(minPQ, tmp, 1);
tmp = tmp->next;
}
distTo[0] = 0;
while (isQueueEmpty(minPQ) == FALSE && isMarkedAll(distTo, 6) == FALSE) {
EdgePtr minEdge = outQueue(minPQ);
VTYPE from = minEdge->v;
VTYPE to = minEdge->w;
int weight = minEdge->weight;
int toPos = getVertexPos(adj, to);
distTo[toPos] = weight;
insertEdge(spt, from, to, weight);
insertEdge(spt, to, from, weight);
changeWeight(adj, distTo, toPos);
EdgePtr tmp = adj->vertexList[toPos]->firstEdge;
while (tmp != NULL) {
insertEdgeToQueue(spt, minPQ, tmp);
tmp = tmp->next;
}
}
deleteQueue(minPQ);
freeAdj(spt);
}
void main() {
int e[7][3] = {
{ 'A', 'F', 60 },
{ 'A', 'E', 30 },
{ 'A', 'C', 10 },
{ 'F', 'E', 20 },
{ 'E', 'D', 50 },
{ 'D', 'C', 11 },
{ 'C', 'B', 5 },
};
const int e_length_1 = 7;
const int e_length_2 = 3;
VTYPE v[6] = { 'A','F','E','D','C','B' };
const int v_length = 6;
AdjGraphPtr adj = createAdjGraph(v, v_length, e, e_length_1, e_length_2);
dijkstraSPT(adj);
freeAdj(adj);
}
void freeAdj(AdjGraphPtr a) {
for (int i = 0; i < a->vNum; i++) {
if (a->vertexList[i]->firstEdge != NULL) {
EdgePtr tmp = a->vertexList[i]->firstEdge;
while (tmp->next != NULL) {
EdgePtr t = tmp;
tmp = tmp->next;
free(t);
}
free(tmp);
}
free(a->vertexList[i]);
}
free(a);
}
EdgePtr createEdgeNode(VTYPE v, VTYPE w, int weight) {
EdgePtr a = (EdgePtr)malloc(sizeof(Edge));
memset(a, 0, sizeof(Edge));
a->v = v;
a->w = w;
a->weight = weight;
a->next = NULL;
return a;
}
int getVertexPos(const AdjGraphPtr m, const VTYPE key) {
for (int i = 0; i < m->vNum; i++) {
if (m->vertexList[i]->v == key)
return i;
}
return -1;
}
void insertVertex(AdjGraphPtr adj, const VTYPE key) {
for (int i = 0; i < adj->vNum; i++) {
if (adj->vertexList[i]->v == key)
return;
}
VertexPtr vNode = (VertexPtr)malloc(sizeof(Vertex));
memset(vNode, 0, sizeof(Vertex));
vNode->v = key;
vNode->firstEdge = NULL;
adj->vertexList[adj->vNum] = vNode;
adj->vNum++;
}
void insertEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
int pos_a = getVertexPos(adj, a);
EdgePtr avex = createEdgeNode(a, b, weight);
if (adj->vertexList[pos_a]->firstEdge == NULL) {
adj->vertexList[pos_a]->firstEdge = avex;
}
else {
EdgePtr tmp = adj->vertexList[pos_a]->firstEdge;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = avex;
}
}
void addEdge(AdjGraphPtr adj, VTYPE a, VTYPE b, int weight) {
insertEdge(adj, a, b, weight);
insertEdge(adj, b, a, weight);
adj->eNum++;
}
AdjGraphPtr createAdjGraph(VTYPE *v, const int v_length, int *e, const int e_length_1, const int e_length_2) {
AdjGraphPtr adj = (AdjGraphPtr)malloc(sizeof(AdjGraph));
memset(adj, 0, sizeof(AdjGraph));
for (int i = 0; i < v_length; i++) {
insertVertex(adj, v[i]);
}
for (int i = 0; i < e_length_1; i++) {
VTYPE a = *(e + e_length_2 * i + 0);
VTYPE b = *(e + e_length_2 * i + 1);
int weight = *(e + e_length_2 * i + 2);
addEdge(adj, a, b, weight);
}
return adj;
}
void print(int *a, int length) {
for (int i = 0; i < length; i++) {
printf("%d ", a[i]);
}
putchar('\n');
}
QueuePtr createQueue() {
QueuePtr q = (QueuePtr)malloc(sizeof(Queue));
memset(q, 0, sizeof(Queue));
q->size = 0;
q->head = q->tail = NULL;
return q;
}
QueueNodePtr createQueueNode(QUETYPE key) {
QueueNodePtr q = (QueueNodePtr)malloc(sizeof(Queue));
memset(q, 0, sizeof(Queue));
q->next = NULL;
q->data = key;
return q;
}
void insertQueue(QueuePtr q, QUETYPE key, int isSort) {
QueueNodePtr a = createQueueNode(key);
if (q->head == NULL) { //notice
q->head = q->tail = a;
}
else {
q->tail->next = a;
q->tail = a;
}
q->size++;
if (isSort == 1) //自动排序
queueSort(q);
}
QUETYPE outQueue(QueuePtr q) {
QUETYPE v;
if (q->head != NULL) { //notice
v = q->head->data;
QueueNodePtr tmp = q->head->next;
free(q->head);
q->head = tmp;
}
else {
v = NULL;
}
return v;
}
void deleteQueue(QueuePtr q) {
if (q->head != NULL) { //notice
QueueNodePtr tmp = q->head;
QueueNodePtr tmp2;
while (tmp != NULL) {
tmp2 = tmp;
tmp = tmp->next;
free(tmp2);
}
}
free(q);
}
int isQueueEmpty(QueuePtr q) {
if (q->head == q->tail) {
return TRUE;
}
return FALSE;
}