数据结构之图

本文深入探讨图论的基本概念,包括图的定义、存储结构、遍历算法以及最短路径问题的解决方法。详细讲解了深度优先搜索、广度优先搜索、Dijkstra算法和Floyd算法,并提供了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,图论
    定义:图(Graph)是一种非线性的数据结构,形式化描述为:
        Graph= (V,R)
        其中V={vi | vi属于datatype,i=0,1,2...,n-1}是图中的元素vi(称为顶点Vertex)的集合,
        当n=0,V为空集
        
        R={<vi,vj> | vi,vj属于V,且vi,vj之间存在路径,0<=i,j<=n-1}是顶点之间的关系集,
        <vi,vj>为顶点vi,vj之间是否存在路径的判定条件。即若vi,vj之间存在路径,则关系<vi,vj>属于R。
        
    有向图(Digraph):  弧
    无向图(Undigraph): 边
    
    网:若在图的关系<vi,vj>或<vj,vi>上附加一个值w,称w为弧或者边上的权。
    带权的图称为网。(权w具体的含义在图不同领域中的应用而定,如顶点表示城市,权w可以为两个城市的距离等等)
        
    顶点的度:顶点的边或弧的条数
    路径:一点顶点到另一个顶点的方式
    
2,图的存储结构:
    "数组表示法"  "邻接表" "十字链表"
    
    (1),数组表示法,又名邻接矩阵(adjacency matrix)
        G =(V,R)
        可以用两个数组来存储图:
        一个一维数组存储G的顶点集V,
        另外一个二维数组存储G中顶点间的关系集R,该二维数组就是所谓的邻接矩阵。

    typedef char Vtype;//顶点的数据类型
    typedef int Adjtype;//邻接矩阵的类型,其实就是边的权值类型
    typedef struct
    {
        Vtype V[MAXN];//顶点的集合,一维数组
        Adjtype Adj[MAXN][MAXN];//边的集合,二维数组表示,邻接矩阵
        int vexnum;//图中顶点的个数
        int arcnum;//图中边的条数        
    }mgraph;

 (2)邻接表
        所谓邻接表(Adjcency Lists)是将图中的每一个顶点V和由V发出的弧或者边构成一个单链表。

    struct adj//邻结结点类型
    {
        int termIndex;//边的终点在顶点数组中的下标
        int w;//权值
        struct adj* next;
    };
    
    struct Vertex//起始顶点的类型
    {
        Vtype data;
        struct adj*first;
    };
    
    struct Vertex graph[MAXN];//起始结点数组

3,图的遍历
    图的遍历是树的遍历的一种推广,是按照某种规划(或次序)访问图中各顶点一次且仅一次的操作,
    亦是将网状结构按照某种规则线性化的过程。
    对图的遍历通常有"深度优先搜索"和"广度优先搜索"的方法。
    
    (1)深度优先搜索算法(DFS:Depth First Search)
        设初始化时,图中的各个顶点均未被访问,从图中某个顶点(设为v0)出发,访问v0,
        然后搜索v0的一个邻接点vi,若vi未被访问,则访问之,再搜索vi的一个邻接点(深度优先),....
        若某顶点的邻接点全部访问完毕,则回溯(Backtracking)到它的上一个顶点,然后再从此顶点又
        按照深度优先的方法搜索下去,。。。直到所有的顶点都访问完毕。
        
    (2)广度优先搜索算法(BFS:Breadth First Search)
        类似树的层次遍历,初始时,图中各顶点均未被访问,从图中的某一个顶点(v0)出发,访问v0,
        并依次访问v0的各个邻接点(广度优先),然后,分别从这些访问过的顶点出发,再按照广度优先的
        搜索方式搜索其他的顶点,。。。直到能访问的顶点都访问完毕为止。
        
4,最短路径问题
    解决带权的有向图中两顶点之间的最短路径问题有两个经典算法:
    Dijkstra(迪杰斯特拉)算法和Floyd(弗洛伊德)算法
    
    Dijkstra算法:是解决从网络中任一顶点(源点)出发,求它到其它各顶点(终点)的最短路径问题。
    算法思路:按照路径的长度递增次序产生从某源点v到图中其余各顶点的最短路径。
    
    Dijkstra算法需要用到两个辅助向量:
    (1)向量 s[n]
        s[i] == 1,表示从源点v到该点vi的最短路径已经求出来了
        s[i] == 0,表示从源点v到该点vi的最短路径还没有求出来
        
    初始化时,s[v]=1,其他s[i]=0(0<= i <=n-1,i不等于v)
    
    (2)向量 dist[n]
        dist[n]存放从源点v到vi这个点的(当前的)最短路径长度
        
    初始化时
        当v可以直接到vi,dist[i] =<v,vi>的权w
        当v不可以直接到vi,dist[i] = 无穷大
        
    算法步骤:
    step1 :显然,从源点v到其它个顶点的第一条最短路径长度dist[u],
        dist[u] = min{dist[w] | w=0,1,2,...n-1,且s[w]=0}
        表示在所有未求出的当前最短路径中找出一条最短的,其长度作为    当前求出的最短路径长度。
    step2:
        对s[w]=0的w,如果dist[u]+<u,w> < dist[w]
        ==>dist[w] = dist[u] + <u,w>
    然后重复step1,step2直到所有的s[n]都等于1为止。
    

图的代码及分析

#include <stdio.h>
#include <stdlib.h>
/*************************************************************************************
'\n'与'\t','空格'的区别:
用'\n'可以刷出缓存区里面的东西,用别的只能等主函数结束才能显示缓存区里的东西;
例如:        程序中间某部分出现死循环时,其之前存的东西在缓存区内,
只有在遇到    '\n'    才会显示,否则不会显示;
所以'\n'可以用来判断之前的代码哪里错误!!!!!
用printf("aaa\n");查找死循环位置时也必须以'\n'刷出'aaa'!!!!!
**********************************************************
为什么要用getchar();吸收??
用gets();吸收会出错!!!!!!
用gets()输入时键盘上是以回车符('\n')结束输入的,
最终会自动在最后添加一个'\0'符,'\n'符也依然存在,
但是下次会被第一个输入数据覆盖,所以没有存在的意义!!

用scanf()输入时键盘上是以回车符('\n')结束输入的,
最终'\n'符依然存在,
连续使用scanf()输入时会将这个'\n'赋作为你输入的第一个字符,以空格形式存在。
(虽然你这次并没有在第一个字符处输入'\n'!!!!!!)
***********************************************/
#define MAXN 1024        //建造大数组:容量为1024
#define W_MAX 65535        //表示顶点间的关系:距离为65535(无穷大)


typedef char Vtype;//顶点的数据类型
typedef int Adjtype;//邻接矩阵的类型,其实就是边的权值类型
/***********************************
图包含的数据为:
1.顶点(有许多顶点,但是不知道具体多少个
所以用一个很大的数组来表示;
    !!!!该一维数组里面放顶点!!!!!!
2.边的集合(所有顶点连成一条线,用两条相同的垂直的线构成一个面)
即构造一个二维数组,数组行跟列都是你所有顶点构成的那条线
长度和内容都相同;
    !!!!该二维数组里面放行顶点到列顶点的权!!!!!
3.图中顶点的个数(用来决定面的面积)
    !!!!决定两个数组能取到的最大下标的值!!!!!!!!
4.图中边的条数(一点顶点直接到另一个顶点的一种方式称为一条边)的总和
    什么是边??
    一点顶点直接到另一个顶点的(一种方式)称为(一条边)
**********************************/

typedef struct
{
    Vtype V[MAXN];//顶点的集合,一维数组
    Adjtype Adj[MAXN][MAXN];//边的集合,二维数组表示,邻接矩阵
    int vexnum;//图中顶点的个数
    int arcnum;//图中边的条数
}mgraph;

/*    返回元素字符x 顶点数组V中的下标,
    n为顶点数组V数组的个数
    如果没有找到则返回-1
*/
/***************************************
定义一个函数专门用来寻找字符X在数组中的位置,
若X存在,返回X在数组中的下标,否则返回-1;
需要传入的参数:
1.数组
2.数组的最大下标(数组容量)
3.需要查找的字符X

使用函数是为了实现功能模块化,易于查错和多次使用
***************************************/
int find_index(Vtype *V,int n,char x)    //寻找并返回字符X在数组中的位置
{
    int i=0;
    for(i=0;i<n;i++)
    {
        if(V[i] == x)
//    if(g->V[i] == 'x')    //错误!!!!!!
    //这样写是判断g->V[i]是否等于字符x的ASCII码值
        {
            return i;
        }
    }

    return -1;
}

/*创建图*/
/**************************************************
1.创建一个空的图(初始化):
    顶点个数和边的条数都为0;
    顶点和顶点之间的关系后面再建立;
2.给图赋顶点:
    赋值进去一个vexnum加一;
3.给图的顶点之间赋权(先找位置,再填充二维数组;):
    先定义两个字符代表两个顶点,把这两个顶点放到查找函数中找到他们的位置
    第一个顶点的返回值作为二维数组的行,
    第二个顶点的返回值作为二维数组的列,
    再定义一个数字作为这两个顶点之间的权(关系),
    最后判断这两个顶点是否存在?
    若存在,就将权装进二维数组中对应的位置

********************************************/
mgraph * create_graph()
{    //1.创建一个空的图(初始化):
    mgraph *g = malloc(sizeof(*g));
    g->vexnum = 0;
    g->arcnum = 0;

    printf("please input the vertex string:\n");
    char str[MAXN];
    gets(str);    //一次性给所以顶点赋值(得到一个字符串)

    /*step1:给顶点数组赋值*/
    int i=0,j;
    while(str[i] != '\0')        //将字符串逐个装进顶点集合这个数组中
    {
        g->V[i] = str[i];
        i++;
    }
    g->vexnum = i;        //统计出顶点个数

    /*
        step2:给邻接矩阵赋值
    */
    for(i=0;i<g->vexnum;i++)        //将边的集合初始化(二维数组所以元素全部置65535)
    {        
        for(j=0;j<g->vexnum;j++)
        {
            g->Adj[i][j] = W_MAX;
        }
    }

    
    //此时已经得到了已被赋值的顶点数组(一维数组)和未被赋值的边的集合(二维数组)
    printf("please input the arc\n");
    while(1)
    {
        Vtype s,p;    //定义两个字符,用来存放自己要建立关系的两个顶点
        Adjtype w;    //定义一个数字,用来存放两个顶点之间的权(关系)
        scanf("%c%c%d",&s,&p,&w);
        getchar();//吸收'\n'

        if(s == '#')        //若我输入的是‘#’,跳出循环,停止建立顶点之间的关系
        {
            break;
        }

        int si,pi;
        si = find_index(g->V,g->vexnum,s);    //寻找并返回顶点s在数组中的位置
        pi = find_index(g->V,g->vexnum,p);    //寻找并返回顶点p在数组中的位置

        if(si!=-1 && pi!= -1)
        {        //如果顶点数组中s和p这两个顶点都找到了!!!
            g->Adj[si][pi] = w;        
            //将两个顶点之间的权放进边的集合(表示出这两个顶点之间的权)!!
            g->arcnum++;        //边的条数加 1
        }
        
    }

    return g;    //返回建立好的整个图
}
/***************************************************
把整个图打印出来
    即打印出顶点数组
*****************************************/
void print_graph(mgraph *g)
{
    putchar('\t');
    int i=0,j;
    for(i=0;i<g->vexnum;i++)    //i小于顶点个数
    {
        printf("%c\t",g->V[i]);    //打印表格的行(横)
    }
    putchar('\n');

    for(i=0;i<g->vexnum;i++)
    {
        printf("%c\t",g->V[i]);        //打印表格的列(纵)
        for(j=0;j<g->vexnum;j++)
        {
            if(g->Adj[i][j] == W_MAX)    //若没有赋权
            {
                printf("#\t");        //打印#
            }
            else
            {
                printf("%d\t",g->Adj[i][j]);    //否则就把权打印出来
            }
        }
        putchar('\n');        
    }
}

/*==========深度优先搜索算法=========*/
int visited[MAXN];//访问标识数组,表示相应的顶点是否已经被访问过
                //为1表示已经被访问过了,0表示没有被访问
/*********************************************************
定义一个全局变量(数组)作为顶点是否打印过的标志    
先统一赋初值,        在DFSTraverse(mgraph *g中把他全部置0了)
若没打印过里面存的就是初值,
若打印过,就把初值改了

要学会使用全局变量!!!!!!!!!!!!!!!!!            
***************************************/
/*找到图g中第v个顶点的第一个邻接点的下标*/
int FirstAdjVex(mgraph *g,int v)        //找到图g中第v个顶点的第一个邻接点的下标
{    //传入图和数字V(v作为数组的下标)
    int i;
    for(i=0;i<g->vexnum;i++)
    {
        if(g->Adj[v][i] != W_MAX)    //若这个位置存在权
        {
            return i;                //将这个权的行下标 i 返回给主调函数
        }
    }

    return -1;        //不存在就返回    -1
}

/************************************************************
从图g中找出第v个顶点的下标为w的邻接点的后面那个邻接点的下标
第w个邻接点在上一轮已经被访问过了,所以从w+1开始查找!!!!!
**********************************************/
int NextAdjVex(mgraph *g,int v,int w)
{//传入图和数字V(v作为数组的下标)和数字w(w+1作为本次循环查找的起始位置)
    int i;
    for(i=w+1;i<g->vexnum;i++)        //w+1作为本次循环查找的起始位置,
    {    //因为w在上次已经被提取出来了,所以这次从w+1开始查找!!!!!
        if(g->Adj[v][i] != W_MAX)
        {
            return i;
        }
    }
    
    return -1;
}

/*从图g中的第v个顶点出发,按照深度优先搜索的方法去【访问】,输出的是顶点*/
/****************************************************************
函数    void DFS(mgraph *g,int v)    传入整个(图g)和一个顶点在顶点数组(一维数组)中的(下标V),
1.把顶点v的标志位置1;
2.打印该顶点;
3.得到该顶点的第一个邻接顶点在顶点数组(一维数组)中的(下标w),
4.判断第w个顶点有没有被访问过:
(1).被访问过,其标志位为 0 (visited[w] == 0)
    将整个(图g)和该顶点的第一个邻接顶点在顶点数组(一维数组)中的(下标w)
    传入函数    void DFS(mgraph *g,int w)    中(传给他本身,从头到尾再执行一次,
    如果满足条件就再传给他本身,从头到尾再执行一次,如此循环直到某次条件不满足开始逐层跳出,
    (最内层完整执行完后向外一层执行【递归形式那行代码】之后的代码,直到外层函数执行完才开始执行他外面那层的);
(2).否则循环结束!!

注意:递归调用他本身时进入函数时是由外层到内存递归,
执行完了跳出函数时是由最内层一层层向外执行再跳出的。
若把一个函数表示成一个房间,那递归就是在最开始的房间里再建造N个房间,N为递归次数(函数层数),
你要从这个房子的前门进入后门出去,就必须先走进N个前门,进入最内存的房间,再走出N个后面才可以!!!
    !!!!!!!容易让人误认为进入最内层房间后直接跳出所有房间,
其实出了小房间,小房间外层的大房间里没走完的路依然要一步步走完!!!!!!!!

    
**********************************/
void DFS(mgraph *g,int v)
{
    visited[v] = 1;        //将visited[v]置    1    (访问并打印了顶点V[v])
    //visited[]为存储标志位的数组    
    printf("%c ",g->V[v]);        //打印出顶点V[v];

    /*得到v的第一个邻接点的下标w,

    如果它没有被访问,就按照DFS的方法去访问它*/
    int w;
    for(w=FirstAdjVex(g,v);w>=0;w=NextAdjVex(g,v,w))
        //找到图g中第v个顶点的第一个邻接点的下标赋值给w(作为for循环的起始位置)
    //找出第v个顶点的下标为w的邻接点的后面那个邻接点的下标(作为循环的移动条件)
    {
        if(visited[w] == 0)        //若第w个没有被访问过
        {    //w是v的第一个邻结点
            DFS(g,w);        //调用他本身去访问w
        }
    }
}

/*按深度优先搜索的方式【遍历】图g中的每个顶点*/
/***************************************************************
这里用到了标志位思想;用来避免重复访问
*****************************/
void DFSTraverse(mgraph *g)
{
    printf("DFS: ");
    int i;
    for(i=0;i<g->vexnum;i++)//把访问标识数组清零
    {    //这是个全局变量,用了全局变量不用再把数组名传给被调函数了,不容易出错
        visited[i] = 0;
    }    //先全部至0,表示一个都没有访问过,有这个标识在就能【避免重复访问】!!!!!!

    for(i=0;i<g->vexnum;i++)//从图g的第i个顶点出发用DFS方式去遍历图
    {
        if(visited[i] == 0)
        {
            DFS(g,i);    //首次调用递归函数,给出第一个顶点的下标
        }
    }

    printf("\n");
}

/*=============广度优先搜索=============*/
/***********************************************************************************
typedef int ElemType;
struct node
{
    ElemType data;
    struct node* next;
    struct node* prev;
};
struct linkQueue
{
    struct node* front;
    struct node* rear;
    int length;
    int max;
};
struct linkQueue* creatQueue(int max)
{
    struct linkQueue*q=(struct linkQueue*)malloc(sizeof(struct linkQueue));
    q->front=NULL;
    q->rear=NULL;
    q->length=0;
    q->max=max;
    return q;
}

int  isEmpty(struct linkQueue * q)
{
    if(q->length==0)//q->rear==NULL  ||q->front==NULL
    {
        return 1;
    }
    return 0;

}
void enQueue(struct linkQueue * q, ElemType data)
{
    
    //1.创建结点
    
    struct node*pNew=(struct node*)malloc(sizeof(*pNew));
    pNew->data=data;
    pNew->next=NULL;
    pNew->prev=NULL;
    //2.入队
    q->length++;
    if(q->front==NULL)
    {
        q->front=q->rear=pNew;
    }
    else
    {

        q->rear->next=pNew;
        pNew->prev=q->rear;
        q->rear=pNew;
    }
    

}
ElemType deQueue(struct linkQueue * q)
{

    if(isEmpty( q))
    {
        return 0;
    }
    //2.删除结点
    int  data=q->front->data;
    struct node*h=q->front;
    q->length--;
    if(q->front==q->rear)
    {
        free(h);
        q->front=NULL;
        q->rear=NULL;
    }
    else
    {
        
        
        q->front=q->front->next;
        q->front->prev=NULL;
        h->next=NULL;
        free(h);
    }
    return data;


}

//广度优先搜索:BFS
void BFSTraverse(mgraph *g)
{
    printf("BFS: ");
    int i;
    for(i=0;i<g->vexnum;i++)//访问标识数组置0
    {
        visited[i] = 0;
    }

    struct linkQueue* lq = creatQueue(g->vexnum);//初始化一个队列
    
    for(i=0;i<g->vexnum;i++)
    {
        if(visited[i] == 0)
        {
            visited[i] = 1;
            printf("%c ",g->V[i]);//访问
            enQueue(lq, i);//把访问过的顶点如队列
            while( !isEmpty(lq))
            {
                int j = deQueue(lq);//出队
                int w;
                for(w=FirstAdjVex(g,j);w>=0;w=NextAdjVex(g,j, w))
                {
                    if(visited[w] == 0)
                    {
                        visited[w] = 1;
                        printf("%c ",g->V[w]);
                        enQueue(lq, w);
                    }
                }
            }
        }
    }
    
    putchar('\n');
}
*********************************************/
/*用Dijkstra算法求出从v点到其它各定点的最短路径长度*/
int s[MAXN];//是否求出最短路径的标志数组
//标志是否求出最短路径,是就置    1,否则置    0

int dist[MAXN];//存放当前到各点的最短路径长度
//当出现比他小的时,数组中的元素随时更新
void Dijkstra(mgraph *g,int v)
{//v为我设置的源顶点
    /*初始时,把s[n],dist[n]初始化*/
    int i;
    for(i=0;i<g->vexnum;i++)
    {
        s[i] = 0;    //将所有标志位全部初始化(置    0)
        dist[i]= g->Adj[v][i];    //读入下标为v的顶点到各顶点之间的权的初始值
    }
    dist[v] = 0;    //将他本身值0,(他到自己的权)
    s[v] = 1;        //将他本身的标志位置    1


    int min;//源点到当前最优顶点的路径长度
    int min_i;//当前最优顶点的下标
    int times;//寻找最短路径的次数,每次找到一条
    for(times=0;times<g->vexnum-1;times++)
    {    //最多能找到顶点数减 1 条路径
        /*step1:找到当前最优顶点,同时找到一条最短路径*/
        for(i=0;i<g->vexnum;i++)//保证min为没有求出最短路径中的dist数组里的某一个值
        {
            if(s[i] == 0)        //若没有找到最佳路径
            {
                min = dist[i];    //将当前v点到下标为i的这个点的长度赋给min
                break;
            }
        }
        
        for(i=0;i<g->vexnum;i++)
        {    //从第一个点开始寻找最短路径直到最后一个点
//    if(S[i]==0&&min<=dist[i])    错误!!有比他短的才更新
            if(s[i] == 0 && dist[i] <= min)        
            {//若i点还没找到最短路径且当前路径比之前的路径短
                min = dist[i];    //更新最短路径的长度
                min_i = i;//更新最短路径的下标
            }
        }
        s[min_i] =1;//当与所以路径都比较完之后,将标志位置 1
        
        /*step2 :更新dist数组*/
        for(i=0;i<g->vexnum;i++)
        {
            if(s[i]==0)
            {    //将还没找到最短路径的顶点
                if(dist[min_i]+g->Adj[min_i][i] < dist[i])
                {
                    dist[i] = dist[min_i] + g->Adj[min_i][i];
                }
            }
        }        
    }
}
/*************************************************************
这个函数只执行了一次,
输入的是整个图和图中的一个顶点,
执行的操作是填充用来存放【顶点v到各个顶点的最短距离】(权的最小值);
这个函数虽然没有返回值,也没有改变过传进去的东西,
但是给一个全局变量赋值了!!
在后面的主函数中可以直接使用这个填充过的数组!!!
*****************************************************************/

/************************************************************************
初始化后:dest[g->Vnum]={0,15,2,12,W_MAX,W_MAX,W_MAX};    //源点下标为 0
times=0:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
    0排除
得到min=2(离源点最近的点的距离为2),min_i=2(这个点的下标为2)//标记S[2]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为2的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[2]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[4]=2+8=10<W_MAX;更新
dest[5]=2+4=6<W_MAX;更新
dest[6]=2+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,12,10,6,W_MAX};

times=1:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,12,10,6,W_MAX};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
    2排除
得到min=6(离源点最近的点的距离为6),min_i=5(这个点的下标为5)    //标记s[5]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为5的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[5]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[3]=6+5=11<12;更新
dest[6]=6+10=16<W_MAX;更新
dest[g->Vnum]={0,15,2,11,10,6,16};

times=2:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,16};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
    6排除
得到min=10(离源点最近的点的距离为10),min_i=4(这个点的下标为4)    //标记s[5]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为4的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[4]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[2]=10+W_MAX>W_MAX;不更新
dest[6]=10+9=19>16;不更新
dest[g->Vnum]={0,15,2,11,10,6,16};

times=3:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,16};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
    10排除
得到min=11(离源点最近的点的距离为11),min_i=4(这个点的下标为3)    //标记s[3]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为4的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[3]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[6]=11+3=14<16;更新
dest[g->Vnum]={0,15,2,11,10,6,14};

times=4:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,14};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
    11排除
得到min=14(离源点最近的点的距离为14),min_i=6(这个点的下标为6)    //标记s[6]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为6的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[6]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[2]=14+4=18>15;不更新
dest[5]=14+W_MAX>W_MAX;不更新
dest[4]=14+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,11,10,6,14};

times=5:    for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)    
if(S[i]==0&&dest[i]<=min)    
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,14};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
    14排除
得到min=15(离源点最近的点的距离为14),min_i=1(这个点的下标为1)    //标记s[1]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为6的顶点最近的顶点的距离计算出来(路线为    源点---> g->V[1]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[4]=15+6>10;不更新
dest[6]=15+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,11,10,6,14};

最终数组为:dest[g->Vnum]={0,15,2,11,10,6,14};
*************************************************************************/

int main()
{
    mgraph *g = create_graph();    //得到一个图(顶点,顶点之间的权,顶点个数,边的条数等所有信息都有)
    print_graph(g);    //打印这个图
    DFSTraverse(g);//深度优先遍历这个图
    BFSTraverse(g);//广度优先遍历这个图
    int v = 0;
    Dijkstra(g,v);//求这个图的所有顶点到顶点V的最短路径(最小的权)

    int i;
    for(i=0;i<g->vexnum;i++)
    {
        printf("%c->%c path is %d\n",g->V[v],g->V[i],dist[i]);    //打印所有顶点到顶点V的最短路径(最小的权)
    }
    

    return 0;
}


/************************************************************
若没有用getchar()在scanf("%c%c%d",&p,&s,&i);后面
吸收'\n'会导致如下结果,
abcdef
ab5
bc15
cd20
de25
#c5
#d6
    a    b    c    d    e    f    
a    #    #    #    #    #    #    
b    #    #    15    #    #    #    
c    #    #    #    #    #    #    
d    #    #    #    #    #    #    
e    #    #    #    #    #    #    
f    #    #    #    #    #    #    

**************************/

/*********************************************
最终运行结果:
abcdefg                              
ab15
ac2
ad12
be6
ce8
cf4
dg3
eg9
fd5
fg10
gb4
#d5
    a    b    c    d    e    f    g    
a    #    15    2    12    #    #    #    
b    #    #    #    #    6    #    #    
c    #    #    #    #    8    4    #    
d    #    #    #    #    #    #    3    
e    #    #    #    #    #    #    9    
f    #    #    #    5    #    #    10    
g    #    4    #    #    #    #    #    
___________________________________________
a
b
e
g
c
f
d
0    15    2    11    10    6    14    
**************************************************/

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值