Dijstra算法---C语言

很累很累!!!花了快一周的时间,是真的笨 ,不过还是很开心。

具体思考方式如下:

首先  我们要根据图,确定一个邻接矩阵---》可以表示两个顶点之间是否关联,且当关联时可以表示具体的权重。

其次,定义两个数组,集合......例如:一个数组A:用来储存起点到每个顶点的最短距离,数组B:用来储存还没有确定的顶点,以及顶点到起点的距离。

假设起点为:a,设无穷大为 INF, 顶点个数为 :V

然后,确认起点,根据起点初始化数组A和数组B,数组A初始化之后为:A[] ={(a,0)}---》因为此时只确定了起点;数组B初始化之后 B[] = {(b,INF),(c,INF),(d,INF),(e,INF),(f,INF),(g,INF)......,,(z,INF)}

显然此时数组A的长度为:1,数组B的长度为: V-1,当数组A的长度为V时遍历也就结束了

程序,所对应的图。实在是懒得再画一次了。凑活着看看吧。

具体操作:

其实就是对数组A的填充,对数组B的数据删除。

首先根据确定的顶点:a ,寻找其关联的点,然后修改所关联的点到起点a的距离,修改成功之后,得到新的数组B,将数组B中最小的权重值所对应的点添加到数组A中,然后在数组B中删除该点对应的元素;

然后再根据刚刚确定的权重最小的点为新的遍历起点(注意:这里仅仅是新的遍历起点不是换了起点!!!!),再次寻找其关联的点,然后修改所关联的点到起点a的距离。。。一直持续到所有的点遍历完成,也就是数组A的长度 = V。

修改关联点的唯一尺度就是他的本身定义:数组B储存的是每个点到达起点的最短路径。如果最短路径上的点之和  << 该点直接到达起点的权重,那就修改,如果没有那就不修改。

例如:

AB+BC《AC,所以数组B中的元素c的权重要修改为 AB+BC =10 而非原来的 17 

而像这种情况,顶点A和顶点C没有连线,也就是A与C之间不关联 根据初始化 AC = INF(无穷大)所以此时肯定是 AB+BC《AC,所以数组B中的元素c的权重要修改为 AB+BC =10 而非原来的INF。

还有一种情况:

  AB+BC》》AC,所以此时C在数组B中的权重仍然为 7 。

好了最精华的东西,这最中心的内容都在这了。具体细节 在代码中,我注释的很明显。有想法的同学们可以自行优化一下,确实只是为了实现功能没有注意其他的细节。

这次本来是 用java写的 但是中途还是没坚持下来,正确在在最近一周吧java部分的也搞出来。

加油!!!奥利给!!!!

代码如下:

#define _CRT_SECURE_NO_WARNINGS//必须定义在预处理命令之前---》4996
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define  V 5//V:顶点个数
//数据结点
typedef struct node {
	char name;
	int num ;
}node;
typedef struct Node {
    
    node date[V] ;
    int len;
};
//结点初始化
void Inin(Node *& a) {
    a = (Node *)malloc(sizeof(Node));
    int Len =a->len= V;
    //结点中全为1000 意指无穷大
    //初始化 name值
    for (int i = 0; i < Len; i++) {
        a->date[i].name = (char)(65 + i);
        a->date[i].num = 1000;
    }
    
}
//数据的删除
void Delete(Node *& a,char name) {
    int i = a->len,j=0;
    
    while (j < i) {
        if (a->date[j].name == name) {
            break;
        }
        j++;
    }
    while (j < i) {
        a->date[j++] = a->date[j + 1];
    }
    a->len--;
}
//数据修改---》进行关联判断之后,修改num值
void Update(Node*& a, char name, int num) {
    Node* p = a;
    int i = 0,j = 0;
    while (i<p->len) {
        if (p->date[i].name == name) { p->date[i].num = num; }
        i++;
    }
}
//数据判断--->目的:返回最小路径的结点值
node Judge(Node*& a) {
    node s;
    Node* p = a;
    int len = p->len;
    int i, j, k = 10000;
    for (i = 0; i < len; i++) {
        if (p->date[i].num < k) {
            j = i;
            k = p->date[i].num;
        }
       
    }
    s = p->date[j];
    return s;
}
//数据添加---》添加结点值
void add(Node*& a, node s) {
    Node* p = a;
    p->date[p->len++] =s;
    
}
//数据求址1--》根据name找到对应的num
int index(Node* a,int nameNum) {
    char c;
    int i = 0;
    switch (nameNum)
    {
    case 0:c='A'; break;
    case 1:c='B'; break;
    case 2:c='C'; break;
    case 3:c='D'; break;
    case 4:c='E'; break;
    }
    while (a->date[i].name != c) {
        i++;
    }
    return a->date[i].num;
}
//数据求址2--》根据name找到对应的i--->0:A 1:B...
int Index(Node* a, char name) {
    Node* p = a;
    int i=0;
    while (p->date[i].name != name && i<p->len) {
        i++;
    }
    if (p->date[i].name != name) {
        return -1;
    }
    return i;
}
void main() {
    int t[V][V] = {
                {0,1000,2,5,4},
                {1000,0,1,3,3},
                {2,1,0,4,2},
                {5,3,4,0,1000},
                {4,3,2,1000,0}
    };
    Node* U, * S;//S为记录已求出最短路径的顶点;U则是记录还未求出最短路径的顶点--->包含距离
    Inin(U); Inin(S);
    int i = 0, j = 0,k = 0;
    //设置起点
    printf("请设置起点:(注意是大写):\n");
    char First /*= 'E'*/;
    scanf("%c", &First);
    while (i < S->len)
    {
        if (S->date[i].name == First) {
            S->date[0].name = First;
            S->date[0].num = 0;
            S->len = 1;
        }
        i++;
    }
    i = Index(U, S->date[0].name);//从起点开始遍历
    Delete(U, First);
    node t0 = Judge(U);
    t0.name = 'z';//这里的Z是随便定义的字符 ,必须是一个顶点数组中没有的元素
                   //目的是确保在顶点数组中没有找到对应的点从而避免损失一次关联
                   //具体指的是  j==Index(U,t0.name)
    for (k=0; k < V; k++) {
       
        for (j = 0; j < V; j++) {
            if (t[i][j] == 1000 || t[i][j] == 0 || j==Index(U,t0.name)) {
                continue;
            }
            int s = 0;
            if (k == 0) {
                s = t[i][j];
                switch (j)
                {
                case 0: {

                    Update(U, 'A', s); break;
                }
                case 1: {

                    Update(U, 'B', s); break;
                }
                case 2: {
                    Update(U, 'C', s); break;
                }
                case 3: {
                    Update(U, 'D', s); break;
                }
                case 4: {
                    Update(U, 'E', s); break;
                }
                }
            }
            else if ((t[i][j] + t0.num) < index(U, j)) {
                s = t[i][j] + t0.num;
                switch (j)
                {
                case 0: {

                    Update(U, 'A', s); break;
                }
                case 1: {

                    Update(U, 'B', s); break;
                }
                case 2: {
                    Update(U, 'C', s); break;
                }
                case 3: {
                    Update(U, 'D', s); break;
                }
                case 4: {
                    Update(U, 'E', s); break;
                }
                }
            }
            
        }
        node x = Judge(U);
        t0 = x;
        Update(S, x.name, x.num);
        Delete(U, x.name);
        add(S, x);
        if (S->len == V) {
            break;
        }
        switch (x.name)
        {
            case 'A':i = 0; break;
            case 'B':i = 1; break;
            case 'C':i = 2; break;
            case 'D':i = 3; break;
            case 'E':i = 4; break;
        }
    }
    //打印起点到每个顶点最近距离
    for (i=0; i < S->len; i++) {
        printf("( %c , %d )\t", S->date[i].name, S->date[i].num);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值