C语言 最短路径之Dijkstra算法 无向图

Dijkstra算法简介

Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。
这里写图片描述

实现过程

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 <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <assert.h>
#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;
}

猜你喜欢

转载自blog.csdn.net/fpk2014/article/details/80666254
今日推荐