Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3108865
  • 博文数量: 396
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4209
  • 用 户 组: 普通用户
  • 注册时间: 2016-07-04 13:04
文章分类

全部博文(396)

文章存档

2022年(1)

2021年(2)

2020年(8)

2019年(24)

2018年(135)

2017年(158)

2016年(68)

我的朋友

分类: 嵌入式

2018-01-24 16:26:16

迪杰斯特拉算法介绍

迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。

基本思想

??通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算)。

??此外,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。

??初始时,S中只有起点s;U中是除s之外的顶点,并且U中顶点的路径是”起点s到该顶点的路径”。然后,从U中找出路径最短的顶点,并将其加入 到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 … 重复该操作,直到遍历完所有顶点。

操作步骤

(1) 初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为”起点s到该顶点的距离”[例如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。

(2) 从U中选出”距离最短的顶点k”,并将顶点k加入到S中;同时,从U中移除顶点k。

(3) 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。

(4) 重复步骤(2)和(3),直到遍历完所有顶点。

单纯的看上面的理论可能比较难以理解,下面通过实例来对该算法进行说明。

迪杰斯特拉算法图解

以上图G4为例,来对迪杰斯特拉进行算法演示(以第4个顶点D为起点)。

初始状态:S是已计算出最短路径的顶点集合,U是未计算除最短路径的顶点的集合!
第1步:将顶点D加入到S中。
此时,S={D(0)}, U={A(∞),B(∞),C(3),E(4),F(∞),G(∞)}。 注:C(3)表示C到起点D的距离是3。

第2步:将顶点C加入到S中。
上一步操作之后,U中顶点C到起点D的距离最短;因此,将C加入到S中,同时更新U中顶点的距离。以顶点F为例,之前F到D的距离为∞;但是将C加入到S之后,F到D的距离为9=(F,C)+(C,D)。
此时,S={D(0),C(3)}, U={A(∞),B(23),E(4),F(9),G(∞)}。

第3步:将顶点E加入到S中。
上一步操作之后,U中顶点E到起点D的距离最短;因此,将E加入到S中,同时更新U中顶点的距离。还是以顶点F为例,之前F到D的距离为9;但是将E加入到S之后,F到D的距离为6=(F,E)+(E,D)。
此时,S={D(0),C(3),E(4)}, U={A(∞),B(23),F(6),G(12)}。

第4步:将顶点F加入到S中。
此时,S={D(0),C(3),E(4),F(6)}, U={A(22),B(13),G(12)}。

第5步:将顶点G加入到S中。
此时,S={D(0),C(3),E(4),F(6),G(12)}, U={A(22),B(13)}。

第6步:将顶点B加入到S中。
此时,S={D(0),C(3),E(4),F(6),G(12),B(13)}, U={A(22)}。

第7步:将顶点A加入到S中。
此时,S={D(0),C(3),E(4),F(6),G(12),B(13),A(22)}。

此时,起点D到各个顶点的最短距离就计算出来了:A(22) B(13) C(3) D(0) E(4) F(6) G(12)

迪杰斯特拉算法的代码说明

以”邻接矩阵”为例对迪杰斯特拉算法进行说明,对于”邻接表”实现的图在后面会给出相应的源码。

1. 基本定义

// 邻接矩阵 typedef struct _graph
{ char vexs[MAX]; // 顶点集合 int vexnum; // 顶点数 int edgnum; // 边数 int matrix[MAX][MAX]; // 邻接矩阵 }Graph, *PGraph; // 边的结构体 typedef struct _EdgeData
{ char start; // 边的起点 char end; // 边的终点 int weight; // 边的权重 }EData;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Graph是邻接矩阵对应的结构体。
vexs用于保存顶点,vexnum是顶点数,edgnum是边数;matrix则是用于保存矩阵信息的二维数组。例如,matrix[i][j]=1, 则表示”顶点i(即vexs[i])”和”顶点j(即vexs[j])”是邻接点;matrix[i][j]=0,则表示它们不是邻接点。
EData是邻接矩阵边对应的结构体。

2. 迪杰斯特拉算法

/*
 * Dijkstra最短路径。
 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
 *
 * 参数说明:
 *        G -- 图
 *       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
 *     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
 *     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
 */ void dijkstra(Graph G, int vs, int prev[], int dist[])
{ int i,j,k; int min; int tmp; int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。 // 初始化 for (i = 0; i < G.vexnum; i++)
    {
        flag[i] = 0; // 顶点i的最短路径还没获取到。 prev[i] = 0; // 顶点i的前驱顶点为0。 dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。 } // 对"顶点vs"自身进行初始化 flag[vs] = 1;
    dist[vs] = 0; // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。 for (i = 1; i < G.vexnum; i++)
    { // 寻找当前最小的路径; // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。 min = INF; for (j = 0; j < G.vexnum; j++)
        { if (flag[j]==0 && dist[j]<min)
            { min = dist[j];
                k = j;
            }
        } // 标记"顶点k"为已经获取到最短路径 flag[k] = 1; // 修正当前最短路径和前驱顶点 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 for (j = 0; j < G.vexnum; j++)
        {
            tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出 if (flag[j] == 0 && (tmp  < dist[j]) )
            {
                dist[j] = tmp;
                prev[j] = k;
            }
        }
    } // 打印dijkstra最短路径的结果 printf("dijkstra(%c): \n", G.vexs[vs]); for (i = 0; i < G.vexnum; i++)
        printf("  shortest(%c, %c)=%d\n", G.vexs[vs], G.vexs[i], dist[i]);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

迪杰斯特拉算法的源码

这里分别给出”邻接矩阵图”和”邻接表图”的迪杰斯特拉算法源码。

1. 邻接矩阵源码(matrix_udg.c)

/**
 * C: Dijkstra算法获取最短路径(邻接矩阵)
 *
 * @author skywang
 * @date 2014/04/24
 */ #include  #include  #include  #include  #define MAX         100 // 矩阵最大容量 #define INF         (~(0x1<<31)) // 最大值(即0X7FFFFFFF) #define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z'))) #define LENGTH(a)   (sizeof(a)/sizeof(a[0])) // 邻接矩阵 typedef struct _graph
{ char vexs[MAX]; // 顶点集合 int vexnum; // 顶点数 int edgnum; // 边数 int matrix[MAX][MAX]; // 邻接矩阵 }Graph, *PGraph; // 边的结构体 typedef struct _EdgeData
{ char start; // 边的起点 char end; // 边的终点 int weight; // 边的权重 }EData; /*
 * 返回ch在matrix矩阵中的位置
 */ static int get_position(Graph G, char ch)
{ int i; for(i=0; iif(G.vexs[i]==ch) return i; return -1;
} /*
 * 读取一个输入字符
 */ static char read_char()
{ char ch; do {
        ch = getchar();
    } while(!isLetter(ch)); return ch;
} /*
 * 创建图(自己输入)
 */ Graph* create_graph()
{ char c1, c2; int v, e; int i, j, weight, p1, p2;
    Graph* pG; // 输入"顶点数"和"边数" printf("input vertex number: "); scanf("%d", &v); printf("input edge number: "); scanf("%d", &e); if ( v < 1 || e < 1 || (e > (v * (v-1))))
    { printf("input error: invalid parameters!\n"); return NULL;
    } if ((pG=(Graph*)malloc(sizeof(Graph))) == NULL ) return NULL; memset(pG, 0, sizeof(Graph)); // 初始化"顶点数"和"边数" pG->vexnum = v;
    pG->edgnum = e; // 初始化"顶点" for (i = 0; i < pG->vexnum; i++)
    { printf("vertex(%d): ", i);
        pG->vexs[i] = read_char();
    } // 1. 初始化"边"的权值 for (i = 0; i < pG->vexnum; i++)
    { for (j = 0; j < pG->vexnum; j++)
        { if (i==j)
                pG->matrix[i][j] = 0; else pG->matrix[i][j] = INF;
        }
    } // 2. 初始化"边"的权值: 根据用户的输入进行初始化 for (i = 0; i < pG->edgnum; i++)
    { // 读取边的起始顶点,结束顶点,权值 printf("edge(%d):", i);
        c1 = read_char();
        c2 = read_char(); scanf("%d", &weight);

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2); if (p1==-1 || p2==-1)
        { printf("input error: invalid edge!\n"); free(pG); return NULL;
        }

        pG->matrix[p1][p2] = weight;
        pG->matrix[p2][p1] = weight;
    } return pG;
} /*
 * 创建图(用已提供的矩阵)
 */ Graph* create_example_graph()
{ char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int matrix[][9] = { /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ /*A*/ { 0, 12, INF, INF, INF, 16, 14}, /*B*/ { 12, 0, 10, INF, INF, 7, INF}, /*C*/ { INF, 10, 0, 3, 5, 6, INF}, /*D*/ { INF, INF, 3, 0, 4, INF, INF}, /*E*/ { INF, INF, 5, 4, 0, 2, 8}, /*F*/ { 16, 7, 6, INF, 2, 0, 9}, /*G*/ { 14, INF, INF, INF, 8, 9, 0}}; int vlen = LENGTH(vexs); int i, j;
    Graph* pG; // 输入"顶点数"和"边数" if ((pG=(Graph*)malloc(sizeof(Graph))) == NULL ) return NULL; memset(pG, 0, sizeof(Graph)); // 初始化"顶点数" pG->vexnum = vlen; // 初始化"顶点" for (i = 0; i < pG->vexnum; i++)
        pG->vexs[i] = vexs[i]; // 初始化"边" for (i = 0; i < pG->vexnum; i++) for (j = 0; j < pG->vexnum; j++)
            pG->matrix[i][j] = matrix[i][j]; // 统计边的数目 for (i = 0; i < pG->vexnum; i++) for (j = 0; j < pG->vexnum; j++) if (i!=j && pG->matrix[i][j]!=INF)
                pG->edgnum++;
    pG->edgnum /= 2; return pG;
} /*
 * 返回顶点v的第一个邻接顶点的索引,失败则返回-1
 */ static int first_vertex(Graph G, int v)
{ int i; if (v<0 || v>(G.vexnum-1)) return -1; for (i = 0; i < G.vexnum; i++) if (G.matrix[v][i]!=0 && G.matrix[v][i]!=INF) return i; return -1;
} /*
 * 返回顶点v相对于w的下一个邻接顶点的索引,失败则返回-1
 */ static int next_vertix(Graph G, int v, int w)
{ int i; if (v<0 || v>(G.vexnum-1) || w<0 || w>(G.vexnum-1)) return -1; for (i = w + 1; i < G.vexnum; i++) if (G.matrix[v][i]!=0 && G.matrix[v][i]!=INF) return i; return -1;
} /*
 * 深度优先搜索遍历图的递归实现
 */ static void DFS(Graph G, int i, int *visited)
{ int w; 

    visited[i] = 1; printf("%c ", G.vexs[i]); // 遍历该顶点的所有邻接顶点。若是没有访问过,那么继续往下走 for (w = first_vertex(G, i); w >= 0; w = next_vertix(G, i, w))
    { if (!visited[w])
            DFS(G, w, visited);
    }

} /*
 * 深度优先搜索遍历图
 */ void DFSTraverse(Graph G)
{ int i; int visited[MAX]; // 顶点访问标记 // 初始化所有顶点都没有被访问 for (i = 0; i < G.vexnum; i++)
        visited[i] = 0; printf("DFS: "); for (i = 0; i < G.vexnum; i++)
    { //printf("\n== LOOP(%d)\n", i); if (!visited[i])
            DFS(G, i, visited);
    } printf("\n");
} /*
 * 广度优先搜索(类似于树的层次遍历)
 */ void BFS(Graph G)
{ int head = 0; int rear = 0; int queue[MAX]; // 辅组队列 int visited[MAX]; // 顶点访问标记 int i, j, k; for (i = 0; i < G.vexnum; i++)
        visited[i] = 0; printf("BFS: "); for (i = 0; i < G.vexnum; i++)
    { if (!visited[i])
        {
            visited[i] = 1; printf("%c ", G.vexs[i]); queue[rear++] = i; // 入队列 } while (head != rear) 
        {
            j = queue[head++]; // 出队列 for (k = first_vertex(G, j); k >= 0; k = next_vertix(G, j, k)) //k是为访问的邻接顶点 { if (!visited[k])
                {
                    visited[k] = 1; printf("%c ", G.vexs[k]); queue[rear++] = k;
                }
            }
        }
    } printf("\n");
} /*
 * 打印矩阵队列图
 */ void print_graph(Graph G)
{ int i,j; printf("Martix Graph:\n"); for (i = 0; i < G.vexnum; i++)
    { for (j = 0; j < G.vexnum; j++) printf("%10d ", G.matrix[i][j]); printf("\n");
    }
} /*
 * prim最小生成树
 *
 * 参数说明:
 *       G -- 邻接矩阵图
 *   start -- 从图中的第start个元素开始,生成最小树
 */ void prim(Graph G, int start)
{ int min,i,j,k,m,n,sum; int index=0; // prim最小树的索引,即prims数组的索引 char prims[MAX]; // prim最小树的结果数组 int weights[MAX]; // 顶点间边的权值 // prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。 prims[index++] = G.vexs[start]; // 初始化"顶点的权值数组", // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。 for (i = 0; i < G.vexnum; i++ )
        weights[i] = G.matrix[start][i]; // 将第start个顶点的权值初始化为0。 // 可以理解为"第start个顶点到它自身的距离为0"。 weights[start] = 0; for (i = 0; i < G.vexnum; i++)
    { // 由于从start开始的,因此不需要再对第start个顶点进行处理。 if(start == i) continue;

        j = 0;
        k = 0;
        min = INF; // 在未被加入到最小生成树的顶点中,找出权值最小的顶点。 while (j < G.vexnum)
        { // 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。 if (weights[j] != 0 && weights[j] < min)
            {
                min = weights[j];
                k = j;
            }
            j++;
        } // 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。 // 将第k个顶点加入到最小生成树的结果数组中 prims[index++] = G.vexs[k]; // 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。 weights[k] = 0; // 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。 for (j = 0 ; j < G.vexnum; j++)
        { // 当第j个节点没有被处理,并且需要更新时才被更新。 if (weights[j] != 0 && G.matrix[k][j] < weights[j])
                weights[j] = G.matrix[k][j];
        }
    } // 计算最小生成树的权值 sum = 0; for (i = 1; i < index; i++)
    {
        min = INF; // 获取prims[i]在G中的位置 n = get_position(G, prims[i]); // 在vexs[0...i]中,找出到j的权值最小的顶点。 for (j = 0; j < i; j++)
        {
            m = get_position(G, prims[j]); if (G.matrix[m][n]// 打印最小生成树 printf("PRIM(%c)=%d: ", G.vexs[start], sum); for (i = 0; i < index; i++) printf("%c ", prims[i]); printf("\n");
} /* 
 * 获取图中的边
 */ EData* get_edges(Graph G)
{ int i,j; int index=0;
    EData *edges;

    edges = (EData*)malloc(G.edgnum*sizeof(EData)); for (i=0;i < G.vexnum;i++)
    { for (j=i+1;j < G.vexnum;j++)
        { if (G.matrix[i][j]!=INF)
            {
                edges[index].start  = G.vexs[i];
                edges[index].end    = G.vexs[j];
                edges[index].weight = G.matrix[i][j];
                index++;
            }
        }
    } return edges;
} /* 
 * 对边按照权值大小进行排序(由小到大)
 */ void sorted_edges(EData* edges, int elen)
{ int i,j; for (i=0; ifor (j=i+1; jif (edges[i].weight > edges[j].weight)
            { // 交换"第i条边"和"第j条边" EData tmp = edges[i];
                edges[i] = edges[j];
                edges[j] = tmp;
            }
        }
    }
} /*
 * 获取i的终点
 */ int get_end(int vends[], int i)
{ while (vends[i] != 0)
        i = vends[i]; return i;
} /*
 * 克鲁斯卡尔(Kruskal)最小生成树
 */ void kruskal(Graph G)
{ int i,m,n,p1,p2; int length; int index = 0; // rets数组的索引 int vends[MAX]={0}; // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。 EData rets[MAX]; // 结果数组,保存kruskal最小生成树的边 EData *edges; // 图对应的所有边 // 获取"图中所有的边" edges = get_edges(G); // 将边按照"权"的大小进行排序(从小到大) sorted_edges(edges, G.edgnum); for (i=0; i// 获取第i条边的"起点"的序号 p2 = get_position(G, edges[i].end); // 获取第i条边的"终点"的序号 m = get_end(vends, p1); // 获取p1在"已有的最小生成树"中的终点 n = get_end(vends, p2); // 获取p2在"已有的最小生成树"中的终点 // 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路 if (m != n)
        {
            vends[m] = n; // 设置m在"已有的最小生成树"中的终点为n rets[index++] = edges[i]; // 保存结果 }
    } free(edges); // 统计并打印"kruskal最小生成树"的信息 length = 0; for (i = 0; i < index; i++)
        length += rets[i].weight; printf("Kruskal=%d: ", length); for (i = 0; i < index; i++) printf("(%c,%c) ", rets[i].start, rets[i].end); printf("\n");
} /*
 * Dijkstra最短路径。
 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
 *
 * 参数说明:
 *        G -- 图
 *       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
 *     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
 *     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
 */ void dijkstra(Graph G, int vs, int prev[], int dist[])
{ int i,j,k; int min; int tmp; int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。 // 初始化 for (i = 0; i < G.vexnum; i++)
    {
        flag[i] = 0; // 顶点i的最短路径还没获取到。 prev[i] = 0; // 顶点i的前驱顶点为0。 dist[i] = G.matrix[vs][i];// 顶点i的最短路径为"顶点vs"到"顶点i"的权。 } // 对"顶点vs"自身进行初始化 flag[vs] = 1;
    dist[vs] = 0; // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。 for (i = 1; i < G.vexnum; i++)
    { // 寻找当前最小的路径; // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。 min = INF; for (j = 0; j < G.vexnum; j++)
        { if (flag[j]==0 && dist[j]// 标记"顶点k"为已经获取到最短路径 flag[k] = 1; // 修正当前最短路径和前驱顶点 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 for (j = 0; j < G.vexnum; j++)
        {
            tmp = (G.matrix[k][j]==INF ? INF : (min + G.matrix[k][j])); // 防止溢出 if (flag[j] == 0 && (tmp  < dist[j]) )
            {
                dist[j] = tmp;
                prev[j] = k;
            }
        }
    } // 打印dijkstra最短路径的结果 printf("dijkstra(%c): \n", G.vexs[vs]); for (i = 0; i < G.vexnum; i++) printf("  shortest(%c, %c)=%d\n", G.vexs[vs], G.vexs[i], dist[i]);
} void main()
{ int prev[MAX] = {0}; int dist[MAX] = {0};
    Graph* pG; // 自定义"图"(输入矩阵队列) //pG = create_graph(); // 采用已有的"图" pG = create_example_graph(); //print_graph(*pG);       // 打印图 //DFSTraverse(*pG);       // 深度优先遍历 //BFS(*pG);               // 广度优先遍历 //prim(*pG, 0);           // prim算法生成最小生成树 //kruskal(*pG);           // kruskal算法生成最小生成树 // dijkstra算法获取"第4个顶点"到其它各个顶点的最短距离 dijkstra(*pG, 3, prev, dist);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576

2. 邻接表源码(list_udg.c)

/**
 * C: Dijkstra算法获取最短路径(邻接表)
 *
 * @author skywang
 * @date 2014/04/24
 */ #include  #include  #include  #include  #define MAX         100 #define INF         (~(0x1<<31)) // 最大值(即0X7FFFFFFF) #define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z'))) #define LENGTH(a)   (sizeof(a)/sizeof(a[0])) // 邻接表中表对应的链表的顶点 typedef struct _ENode
{ int ivex; // 该边的顶点的位置 int weight; // 该边的权 struct _ENode *next_edge; // 指向下一条弧的指针 }ENode, *PENode; // 邻接表中表的顶点 typedef struct _VNode
{ char data; // 顶点信息 ENode *first_edge; // 指向第一条依附该顶点的弧 }VNode; // 邻接表 typedef struct _LGraph
{ int vexnum; // 图的顶点的数目 int edgnum; // 图的边的数目 VNode vexs[MAX];
}LGraph; /*
 * 返回ch在matrix矩阵中的位置
 */ static int get_position(LGraph G, char ch)
{ int i; for(i=0; iif(G.vexs[i].data==ch) return i; return -1;
} /*
 * 读取一个输入字符
 */ static char read_char()
{ char ch; do {
        ch = getchar();
    } while(!isLetter(ch)); return ch;
} /*
 * 将node链接到list的末尾
 */ static void link_last(ENode *list, ENode *node)
{
    ENode *p = list; while(p->next_edge)
        p = p->next_edge;
    p->next_edge = node;
} /*
 * 创建邻接表对应的图(自己输入)
 */ LGraph* create_lgraph()
{ char c1, c2; int v, e; int i, p1, p2; int weight;
    ENode *node1, *node2;
    LGraph* pG; // 输入"顶点数"和"边数" printf("input vertex number: "); scanf("%d", &v); printf("input edge number: "); scanf("%d", &e); if ( v < 1 || e < 1 || (e > (v * (v-1))))
    { printf("input error: invalid parameters!\n"); return NULL;
    } if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL ) return NULL; memset(pG, 0, sizeof(LGraph)); // 初始化"顶点数"和"边数" pG->vexnum = v;
    pG->edgnum = e; // 初始化"邻接表"的顶点 for(i=0; ivexnum; i++)
    { printf("vertex(%d): ", i);
        pG->vexs[i].data = read_char();
        pG->vexs[i].first_edge = NULL;
    } // 初始化"邻接表"的边 for(i=0; iedgnum; i++)
    { // 读取边的起始顶点,结束顶点,权 printf("edge(%d): ", i);
        c1 = read_char();
        c2 = read_char(); scanf("%d", &weight);

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2); // 初始化node1 node1 = (ENode*)malloc(sizeof(ENode));
        node1->ivex = p2;
        node1->weight = weight; // 将node1链接到"p1所在链表的末尾" if(pG->vexs[p1].first_edge == NULL)
          pG->vexs[p1].first_edge = node1; else link_last(pG->vexs[p1].first_edge, node1); // 初始化node2 node2 = (ENode*)malloc(sizeof(ENode));
        node2->ivex = p1;
        node2->weight = weight; // 将node2链接到"p2所在链表的末尾" if(pG->vexs[p2].first_edge == NULL)
            pG->vexs[p2].first_edge = node2; else link_last(pG->vexs[p2].first_edge, node2);
    } return pG;
} // 边的结构体 typedef struct _edata
{ char start; // 边的起点 char end; // 边的终点 int weight; // 边的权重 }EData; // 顶点 static char gVexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; // 边 static EData gEdges[] = { // 起点 终点 权 {'A', 'B', 12}, 
    {'A', 'F', 16}, 
    {'A', 'G', 14}, 
    {'B', 'C', 10}, 
    {'B', 'F', 7}, 
    {'C', 'D', 3}, 
    {'C', 'E', 5}, 
    {'C', 'F', 6}, 
    {'D', 'E', 4}, 
    {'E', 'F', 2}, 
    {'E', 'G', 8}, 
    {'F', 'G', 9}, 
}; /*
 * 创建邻接表对应的图(用已提供的数据)
 */ LGraph* create_example_lgraph()
{ char c1, c2; int vlen = LENGTH(gVexs); int elen = LENGTH(gEdges); int i, p1, p2; int weight;
    ENode *node1, *node2;
    LGraph* pG; if ((pG=(LGraph*)malloc(sizeof(LGraph))) == NULL ) return NULL; memset(pG, 0, sizeof(LGraph)); // 初始化"顶点数"和"边数" pG->vexnum = vlen;
    pG->edgnum = elen; // 初始化"邻接表"的顶点 for(i=0; ivexnum; i++)
    {
        pG->vexs[i].data = gVexs[i];
        pG->vexs[i].first_edge = NULL;
    } // 初始化"邻接表"的边 for(i=0; iedgnum; i++)
    { // 读取边的起始顶点,结束顶点,权 c1 = gEdges[i].start;
        c2 = gEdges[i].end;
        weight = gEdges[i].weight;

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2); // 初始化node1 node1 = (ENode*)malloc(sizeof(ENode));
        node1->ivex = p2;
        node1->weight = weight; // 将node1链接到"p1所在链表的末尾" if(pG->vexs[p1].first_edge == NULL)
            pG->vexs[p1].first_edge = node1; else link_last(pG->vexs[p1].first_edge, node1); // 初始化node2 node2 = (ENode*)malloc(sizeof(ENode));
        node2->ivex = p1;
        node2->weight = weight; // 将node2链接到"p2所在链表的末尾" if(pG->vexs[p2].first_edge == NULL)
            pG->vexs[p2].first_edge = node2; else link_last(pG->vexs[p2].first_edge, node2);
    } return pG;
} /*
 * 深度优先搜索遍历图的递归实现
 */ static void DFS(LGraph G, int i, int *visited)
{ int w;
    ENode *node;

    visited[i] = 1; printf("%c ", G.vexs[i].data);
    node = G.vexs[i].first_edge; while (node != NULL)
    { if (!visited[node->ivex])
            DFS(G, node->ivex, visited);
        node = node->next_edge;
    }
} /*
 * 深度优先搜索遍历图
 */ void DFSTraverse(LGraph G)
{ int i; int visited[MAX]; // 顶点访问标记 // 初始化所有顶点都没有被访问 for (i = 0; i < G.vexnum; i++)
        visited[i] = 0; printf("DFS: "); for (i = 0; i < G.vexnum; i++)
    { if (!visited[i])
            DFS(G, i, visited);
    } printf("\n");
} /*
 * 广度优先搜索(类似于树的层次遍历)
 */ void BFS(LGraph G)
{ int head = 0; int rear = 0; int queue[MAX]; // 辅组队列 int visited[MAX]; // 顶点访问标记 int i, j, k;
    ENode *node; for (i = 0; i < G.vexnum; i++)
        visited[i] = 0; printf("BFS: "); for (i = 0; i < G.vexnum; i++)
    { if (!visited[i])
        {
            visited[i] = 1; printf("%c ", G.vexs[i].data); queue[rear++] = i; // 入队列 } while (head != rear) 
        {
            j = queue[head++]; // 出队列 node = G.vexs[j].first_edge; while (node != NULL)
            {
                k = node->ivex; if (!visited[k])
                {
                    visited[k] = 1; printf("%c ", G.vexs[k].data); queue[rear++] = k;
                }
                node = node->next_edge;
            }
        }
    } printf("\n");
} /*
 * 打印邻接表图
 */ void print_lgraph(LGraph G)
{ int i,j;
    ENode *node; printf("List Graph:\n"); for (i = 0; i < G.vexnum; i++)
    { printf("%d(%c): ", i, G.vexs[i].data);
        node = G.vexs[i].first_edge; while (node != NULL)
        { printf("%d(%c) ", node->ivex, G.vexs[node->ivex].data);
            node = node->next_edge;
        } printf("\n");
    }
} /*
 * 获取G中边的权值;若start和end不是连通的,则返回无穷大。
 */ int get_weight(LGraph G, int start, int end)
{
    ENode *node; if (start==end) return 0;

    node = G.vexs[start].first_edge; while (node!=NULL)
    { if (end==node->ivex) return node->weight;
        node = node->next_edge;
    } return INF;
} /*
 * prim最小生成树
 *
 * 参数说明:
 *       G -- 邻接表图
 *   start -- 从图中的第start个元素开始,生成最小树
 */ void prim(LGraph G, int start)
{ int min,i,j,k,m,n,tmp,sum; int index=0; // prim最小树的索引,即prims数组的索引 char prims[MAX]; // prim最小树的结果数组 int weights[MAX]; // 顶点间边的权值 // prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。 prims[index++] = G.vexs[start].data; // 初始化"顶点的权值数组", // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。 for (i = 0; i < G.vexnum; i++ )
        weights[i] = get_weight(G, start, i); for (i = 0; i < G.vexnum; i++)
    { // 由于从start开始的,因此不需要再对第start个顶点进行处理。 if(start == i) continue;

        j = 0;
        k = 0;
        min = INF; // 在未被加入到最小生成树的顶点中,找出权值最小的顶点。 while (j < G.vexnum)
        { // 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。 if (weights[j] != 0 && weights[j] < min)
            {
                min = weights[j];
                k = j;
            }
            j++;
        } // 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。 // 将第k个顶点加入到最小生成树的结果数组中 prims[index++] = G.vexs[k].data; // 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。 weights[k] = 0; // 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。 for (j = 0 ; j < G.vexnum; j++)
        { // 获取第k个顶点到第j个顶点的权值 tmp = get_weight(G, k, j); // 当第j个节点没有被处理,并且需要更新时才被更新。 if (weights[j] != 0 && tmp < weights[j])
                weights[j] = tmp;
        }
    } // 计算最小生成树的权值 sum = 0; for (i = 1; i < index; i++)
    {
        min = INF; // 获取prims[i]在G中的位置 n = get_position(G, prims[i]); // 在vexs[0...i]中,找出到j的权值最小的顶点。 for (j = 0; j < i; j++)
        {
            m = get_position(G, prims[j]);
            tmp = get_weight(G, m, n); if (tmp < min)
                min = tmp;
        }
        sum += min;
    } // 打印最小生成树 printf("PRIM(%c)=%d: ", G.vexs[start].data, sum); for (i = 0; i < index; i++) printf("%c ", prims[i]); printf("\n");
} /* 
 * 获取图中的边
 */ EData* get_edges(LGraph G)
{ int i,j; int index=0;
    ENode *node;
    EData *edges;

    edges = (EData*)malloc(G.edgnum*sizeof(EData)); for (i=0; iwhile (node != NULL)
        { if (node->ivex > i)
            {
                edges[index].start  = G.vexs[i].data; // 起点 edges[index].end    = G.vexs[node->ivex].data; // 终点 edges[index].weight = node->weight; // 权 index++;
            }
            node = node->next_edge;
        }
    } return edges;
} /* 
 * 对边按照权值大小进行排序(由小到大)
 */ void sorted_edges(EData* edges, int elen)
{ int i,j; for (i=0; ifor (j=i+1; jif (edges[i].weight > edges[j].weight)
            { // 交换"第i条边"和"第j条边" EData tmp = edges[i];
                edges[i] = edges[j];
                edges[j] = tmp;
            }
        }
    }
} /*
 * 获取i的终点
 */ int get_end(int vends[], int i)
{ while (vends[i] != 0)
        i = vends[i]; return i;
} /*
 * 克鲁斯卡尔(Kruskal)最小生成树
 */ void kruskal(LGraph G)
{ int i,m,n,p1,p2; int length; int index = 0; // rets数组的索引 int vends[MAX]={0}; // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。 EData rets[MAX]; // 结果数组,保存kruskal最小生成树的边 EData *edges; // 图对应的所有边 // 获取"图中所有的边" edges = get_edges(G); // 将边按照"权"的大小进行排序(从小到大) sorted_edges(edges, G.edgnum); for (i=0; i// 获取第i条边的"起点"的序号 p2 = get_position(G, edges[i].end); // 获取第i条边的"终点"的序号 m = get_end(vends, p1); // 获取p1在"已有的最小生成树"中的终点 n = get_end(vends, p2); // 获取p2在"已有的最小生成树"中的终点 // 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路 if (m != n)
        {
            vends[m] = n; // 设置m在"已有的最小生成树"中的终点为n rets[index++] = edges[i]; // 保存结果 }
    } free(edges); // 统计并打印"kruskal最小生成树"的信息 length = 0; for (i = 0; i < index; i++)
        length += rets[i].weight; printf("Kruskal=%d: ", length); for (i = 0; i < index; i++) printf("(%c,%c) ", rets[i].start, rets[i].end); printf("\n");
} /*
 * Dijkstra最短路径。
 * 即,统计图(G)中"顶点vs"到其它各个顶点的最短路径。
 *
 * 参数说明:
 *        G -- 图
 *       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。
 *     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。
 *     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。
 */ void dijkstra(LGraph G, int vs, int prev[], int dist[])
{ int i,j,k; int min; int tmp; int flag[MAX]; // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。 // 初始化 for (i = 0; i < G.vexnum; i++)
    {
        flag[i] = 0; // 顶点i的最短路径还没获取到。 prev[i] = 0; // 顶点i的前驱顶点为0。 dist[i] = get_weight(G, vs, i); // 顶点i的最短路径为"顶点vs"到"顶点i"的权。 } // 对"顶点vs"自身进行初始化 flag[vs] = 1;
    dist[vs] = 0; // 遍历G.vexnum-1次;每次找出一个顶点的最短路径。 for (i = 1; i < G.vexnum; i++)
    { // 寻找当前最小的路径; // 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。 min = INF; for (j = 0; j < G.vexnum; j++)
        { if (flag[j]==0 && dist[j]// 标记"顶点k"为已经获取到最短路径 flag[k] = 1; // 修正当前最短路径和前驱顶点 // 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 for (j = 0; j < G.vexnum; j++)
        {
            tmp = get_weight(G, k, j);
            tmp = (tmp==INF ? INF : (min + tmp)); // 防止溢出 if (flag[j] == 0 && (tmp  < dist[j]) )
            {
                dist[j] = tmp;
                prev[j] = k;
            }
        }
    } // 打印dijkstra最短路径的结果 printf("dijkstra(%c): \n", G.vexs[vs].data); for (i = 0; i < G.vexnum; i++) printf("  shortest(%c, %c)=%d\n", G.vexs[vs].data, G.vexs[i].data, dist[i]);
} void main()
{ int prev[MAX] = {0}; int dist[MAX] = {0};
    LGraph* pG; // 自定义"图"(自己输入数据) //pG = create_lgraph(); // 采用已有的"图" pG = create_example_lgraph(); //print_lgraph(*pG);    // 打印图 //DFSTraverse(*pG);     // 深度优先遍历 //BFS(*pG);             // 广度优先遍历 //prim(*pG, 0);         // prim算法生成最小生成树 //kruskal(*pG);         // kruskal算法生成最小生成树 // dijkstra算法获取"第4个顶点"到其它各个顶点的最短距离 dijkstra(*pG, 3, prev, dist);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640

转载自:Dijkstra算法(一)之 C语言详解

阅读(3806) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~