| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2303 人关注过本帖
标题:分享图的邻接表深度和广度优先搜索~
只看楼主 加入收藏
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
结帖率:99.25%
收藏
已结贴  问题点数:20 回复次数:10 
分享图的邻接表深度和广度优先搜索~
感觉代码写得比较长~不过还是整理出来了~仅供参考~~~

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

#define MAX                20                //最大边数
#define HEAD_NUM           8                 //顶点实际数量
#define LEN                sizeof (Node)
#define LEN_Qnode          sizeof (Qnode)
#define LEN_LinkQnode      sizeof (LinkQnode)


typedef int ElemType;

typedef struct Node
{
    ElemType vertes;          //顶点信息
    struct Node* next;        //下一个顶点坐标信息

}Node,*PNode;

typedef struct Graph          //图的顶点数组
{
    PNode head;               //头顶点信息
    ElemType vertrs;          //该顶点信息
    int visit;                //该点是否被遍历
}Graph;

typedef struct Data
{
    int n;             //顶点数量
    int e;             //边数
    int node[MAX][2];  //邻接表信息
    Graph graph[MAX];  //邻接表
}Data;

typedef struct Queue    //队列
{
    ElemType current;    //记录顶点信息
    struct Queue* next;  //队列指针
}Qnode,*PQnode;

typedef struct LinkQueue
{
    PQnode front;        //队头指针
    PQnode rear;         //队尾指针 
}LinkQnode,*PLinkQnode;  

void Creat_Init(Data* G);                     //初始化图的信息
void Creat_Node(PNode* p);                    //建立新顶点
void Creat_Graph(Data* G);                    //建立邻接表

void Print_Graph(Data* G);                    //输出邻接表信息
 
void DFS_Search(Graph graph[],int current);         //图的深度搜索
void BFS_Search(Graph graph[],int n);               //图的广度搜索

void Empty_Visit(Data* G);                    //重置遍历状态(用于重新遍历) 
void Del_Graph(Data* G);                      //释放邻接表

void Creat_Queue(PLinkQnode* p);              //新建一个队列
void Creat_Node_Queue(PQnode* p);             //创建一个队列节点
void Insert_Queue(PLinkQnode p,ElemType n);   //入队
void Pop_Queue(PLinkQnode p);                //出队
void Del_Queue(PLinkQnode* p);                //清空队列

int Empty_Queue(PLinkQnode p);                //判断队空

int main()
{
    Data G=
    {
        0,0,

        {
            {1,2},{2,1},
            {1,4},{4,1},
            {3,4},{4,3},
            {1,8},{8,1},
            {2,6},{6,2},
            {4,5},{5,4},
            {5,6},{6,5},
            {6,7},{7,6},
            {6,8},{8,6},
        },
    };

    Creat_Init(&G);
    Creat_Graph(&G);

    Print_Graph(&G);

    puts("\n图的深度搜索结果为:\n");
    printf("搜索起点:%d\n",1);
    DFS_Search(G.graph,1);   //深度搜索

    Empty_Visit(&G);        //重置遍历状态

    puts("\n图的广度搜索结果为:\n");
    BFS_Search(G.graph,1);

    Del_Graph(&G);          //释放邻接表

    return 0;
}

void Creat_Node(PNode* p)  //建立新顶点
{
    *p=(PNode)malloc(LEN);
    assert(*p!=NULL);

    memset(*p,0,LEN);
}

void Creat_Init(Data* G)       //初始化图的信息
{
    int i=0;

    memset(G->graph,0,sizeof(G->graph));

    G->n=HEAD_NUM;
    G->e=MAX;

    for (i=0;i<=G->n;++i)
    {
        Creat_Node(&G->graph[i].head);  //创建头顶点信息
        G->graph[i].vertrs=i;
    }
}

void Creat_Graph(Data* G)
{
    PNode new_node=NULL;  //图的遍历指针
    PNode ptr=NULL;

    int i=0;

    int from=0;      //边的起点
    int to=0;        //边的终点

    for (i=0;i<G->e;++i)         
    {
        from=G->node[i][0];
        to=G->node[i][1];

        Creat_Node(&new_node);           //创建顶点坐标

        new_node->vertes=to;             //建立邻接表
        ptr=G->graph[from].head;

        while (ptr->next!=NULL)  
            ptr=ptr->next;

        ptr->next=new_node;   //插入新节点

    }
}



void Print_Graph(Data* G)           //输出邻接表信息
{
    PNode ptr=NULL;

    int i=0;

    for (i=1;i<=G->n;++i)
    {
        ptr=G->graph[i].head->next;

        printf("vertex[%d]->",G->graph[i].vertrs);

        while (ptr)
        {
            printf("%-3d",ptr->vertes);
            ptr=ptr->next;
        }

        puts("");
    }
}

void DFS_Search(Graph graph[],int current)   //图的深度搜索
{
    PNode ptr=graph[current].head->next;    //遍历顶点指针
    graph[current].visit=1;

    printf("vertex[%d]\n",graph[current].vertrs);

    while (ptr!=NULL)
    {
        if (graph[ptr->vertes].visit==0)    //递归遍历呼叫
            DFS_Search(graph,ptr->vertes);

        ptr=ptr->next;
    }
}

void BFS_Search(Graph graph[],int n)      //图的广度搜索 
{
    PNode ptr=NULL;                  //遍历顶点指针
    PLinkQnode queue=NULL;

    int count[MAX]={0};             //图的步长标记
    int step=1;                     //图的步长

    Creat_Queue(&queue);

    printf("搜索起点:%d\n",n);
    if (graph[n].head!=NULL)
    {
        Insert_Queue(queue,graph[n].vertrs);      //第一个顶点入队
        printf("步长->%-2d vertex[%d]\n",step,graph[n].vertrs);
        graph[n].visit=1;
        count[n]=step;
    }

    while (!Empty_Queue(queue))
    {
        ptr=graph[queue->front->next->current].head->next;

        if (count[queue->front->next->current]==step)
             ++step;

        while (ptr!=NULL)
        {

            if (graph[ptr->vertes].visit==0)
            {
                Insert_Queue(queue,graph[ptr->vertes].vertrs);

                printf("步长->%-2d vertex[%d]\n",step,graph[ptr->vertes].vertrs);

                graph[ptr->vertes].visit=1;
                count[graph[ptr->vertes].vertrs]=step;
            }

            ptr=ptr->next;
        }

        Pop_Queue(queue);
    }

    Del_Queue(&queue);
}

void Empty_Visit(Data* G)      //清空遍历信息 
{
    int i=0;

    for (i=1;i<=G->n;++i)
        G->graph[i].visit=0;
}

void Del_Graph(Data* G)        //释放邻接表
{
    PNode t1=G->graph[0].head;
    PNode t2=t1;

    int i=0;

    for (i=0;i<=G->n;t1=t2=G->graph[++i].head)
    {
        if (G->graph[i].head==NULL)
            continue;

        while (t1=t2)
        {
            t2=t1->next;
            free(t1);
        }

         G->graph[i].head=NULL;
    }
}

void Creat_Queue(PLinkQnode* p)             //新建一个队列
{
    *p=(PLinkQnode)malloc(LEN_LinkQnode);
    assert(*p!=NULL);

    memset(*p,0,LEN_LinkQnode);

    (*p)->front=(*p)->rear=(PQnode)malloc(LEN_Qnode);
    assert((*p)->front!=NULL);

    memset((*p)->front,0,LEN_Qnode);
}

void Creat_Node_Queue(PQnode* p)             //创建一个队列节点
{
    *p=(PQnode)malloc(LEN_Qnode);
    assert(*p!=NULL);

    memset(*p,0,LEN_Qnode);
}

void Insert_Queue(PLinkQnode p,ElemType n)   //入队
{
    PQnode t=NULL;
    Creat_Node_Queue(&t);

    t->current=n;
    p->rear=p->rear->next=t;
}

void Pop_Queue(PLinkQnode p)                //出队
{
    PQnode t1=p->front;

    if (Empty_Queue(p))
        return ;

    p->front=p->front->next;

    free(t1);

    t1=p->front->next;
    memset(p->front,0,LEN_Qnode);
    p->front->next=t1;
}

void Del_Queue(PLinkQnode* p)                //清空队列
{
    PQnode t=(*p)->front;

    while (!Empty_Queue(*p))
        Pop_Queue(*p);

    free(*p);

    *p=NULL;
}

int Empty_Queue(PLinkQnode p)                 //判断队空
{
    return p->front==p->rear;
}




[此贴子已经被作者于2017-4-23 06:01编辑过]

2017-04-23 05:57
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
收藏
得分:7 
回复 楼主 九转星河
抽象数据类型一一图有几个成员函数得自己整出来:插入、删除顶点、边的函数,网上百度不到,教材上也不一定有现成的

一切都在学习、尝试、摸索中
2017-04-23 22:27
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
@renkejun1942
有能力时可以写个泛型图操作来玩玩~大一时要用链表写信息管理系统大二就要用数据结构写城市规划管理系统了就是现在感觉插入和删除顶点和边调整比较麻烦~不过感觉写泛型要和图的结构框架要匹配才行~所以和上楼回复这个感觉的确比较难找到现成的通用性较强的代码~~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-24 05:47
yangfrancis
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:141
帖 子:1510
专家分:7661
注 册:2014-5-19
收藏
得分:7 
草民老眼混花。还是楼主指点一二吧:请问边的权重是哪个变量在管?
2017-04-24 11:13
renkejun1942
Rank: 14Rank: 14Rank: 14Rank: 14
来 自:不是这样
等 级:贵宾
威 望:33
帖 子:1645
专家分:5297
注 册:2016-12-1
收藏
得分:7 
回复 3楼 九转星河
我还没学到哪里去了。
树已经够我折腾好长一段时间了。

关于泛型图,我问了一下我那个程序员朋友,得到一下答复:

图片附件: 游客没有浏览图片的权限,请 登录注册


[此贴子已经被作者于2017-4-24 12:28编辑过]


09:30 05/21 种下琵琶种子,能种活么?等待中……
21:50 05/27 没有发芽。
20:51 05/28 没有发芽。
23:03 05/29 没有发芽。
23:30 06/09 我有预感,要发芽了。
2017-04-24 11:35
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 4楼 yangfrancis
现阶段还没弄加权问题~以后用迪斯特杰拉算法和弗洛伊德算法时就要另外加变量了~感觉邻接矩阵虽然费点空间~但操作起来比较方便~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-24 12:44
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 5楼 renkejun1942
玩笑~就图的结构复杂性而言还是省点脑子吧~~~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-24 12:46
yangfrancis
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:141
帖 子:1510
专家分:7661
注 册:2014-5-19
收藏
得分:0 
回复 6楼 九转星河
同感。邻接矩阵虽浪费空间,的确操作要方便得多,也更直观
2017-04-25 13:22
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
更新了一个邻接矩阵转邻接表以及其深度优先搜索和广度优先搜索~

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

#define MaxVertexNum 20
#define LEN sizeof(EdgeNode)

 
#define INF 999    //定义无穷大

/****************图的邻接矩阵定义 *******************/
typedef char VertexType;      //VertexType----顶点内容
typedef int EdgeType;         //EdgeType----顶点信息
typedef struct                //邻接矩阵
{
    VertexType vexs[MaxVertexNum];               //邻接矩阵顶点内容

    EdgeType visit[MaxVertexNum];
    EdgeType edges[MaxVertexNum][MaxVertexNum];  //邻接矩阵列表
    int n; //n为顶点数 
    int e;//e为边数 
}MGraph;   //定义邻接矩阵


/****************图的邻接表定义 *******************/
typedef struct node   //邻接表节点
{
    VertexType adjvex;      //所在的顶点
    EdgeType info;       //顶点信息
    struct node *next;   //邻接表指针
} EdgeNode;              //定义邻接表

typedef struct vnode
{
    VertexType vertex;      //顶点信息
    EdgeType visit;         //遍历标记
    EdgeNode* firstedge;    //第一个顶点指针
}VertexNode;
typedef struct
{
    int n;                               //顶点数
    int e;                               //边数
    VertexNode AdjList[MaxVertexNum];    //邻接表的保存信息

}ALGraph;                                //邻接表

/****************图的创建与打印 *******************/ 
void CreateMGraph(MGraph* G)
{
    int i=0;
    int j=0;
    int k=0;

    printf("请输入顶点数和边数(输入格式为:顶点数,边数):\n");
    assert(scanf("%d,%d",&(G->n),&(G->e))==2);      /*输入顶点数和边数*/

    getchar();
        

    printf("请输入顶点信息(输入格式为:顶点号<CR>):\n");
    for(i=0;i<G->n;i++)
        assert(scanf("%c%*c",&(G->vexs[i]))==1);
                               /*输入顶点信息,建立顶点表*/
    for(i=0;i<G->n;i++)
    {
        G->visit[i]=0;         /*初始化遍历内容*/
        for(j=0;j<G->n;j++)
          G->edges[i][j]=0;     /*初始化邻接矩阵*/ 
    }

          printf("请输入每条边对应的两个顶点的序号(输入格式为:i,j):\n");
          for(k=0;k<G->e;k++)
          {
              assert(scanf("%d,%d",&i,&j)==2);    /*输入e条边,建立邻接矩阵*/
            G->edges[i][j]=1;            /*若加入G->edges[i][j]=1*/
            G->edges[j][i]=1;           /*则为无向图的邻接矩阵存储建立 */
                                        
          }

    getchar();
}

void printMGraph(MGraph* G)
{
    int i=0;
    int j=0;

    printf("   ");

    for (i=0;i<G->n;++i)
        printf("%c ",G->vexs[i]);

    puts("");

    for(i=0;i<G->n;++i)
    {
        printf("%c->",G->vexs[i]);
        for(j=0;j<G->n;j++)
            printf("%d ",G->edges[i][j]);

        puts("");
    } 
}

void Creat_Node(EdgeNode** node,int size)
{
    *node=(struct node*)malloc(LEN);
    assert(*node);
    memset(*node,0,size);
}

void MGraphtoALGraph(MGraph* mG,ALGraph* alG)   //邻接矩阵转化为邻接表
{
    int i=0;
    int j=0;

    EdgeNode* p=NULL;

    alG->e=mG->e;
    alG->n=mG->n;

    for (i=0;i<mG->n;++i)
    {
        Creat_Node(&p,LEN);

        alG->AdjList[i].firstedge=p;
        alG->AdjList[i].vertex=mG->vexs[i];
        alG->AdjList[i].firstedge->info=i;
        alG->AdjList[i].visit=0;              

        for (j=0;j<mG->n;++j)
            if (mG->edges[i][j])
            {
                EdgeNode* new_p=NULL;
                Creat_Node(&new_p,LEN);
                new_p->adjvex=mG->vexs[j];
                new_p->info=j;

                p=p->next=new_p;
            }
    }
}



void printALGraph(ALGraph* alG)          //打印邻接表
{
    EdgeNode* p=NULL;

    int i=0;

    for (i=0;i<alG->n;++i)
    {
        p=alG->AdjList[i].firstedge;
        printf("%c->",alG->AdjList[i].vertex);

        while (p)
        {
            printf("%c ",p->adjvex);
            p=p->next;
        }

        puts("");
    }
}

/****************图的深度优先遍历 *******************/
void MG_DFSTraverse(MGraph* mG,EdgeType Col)  //矩阵的列
{
    int i=0;

    mG->visit[Col]=1;

    printf("vertex->%c\n",mG->vexs[Col]);

    for (i=0;i<mG->n;++i)
        if (mG->visit[i]==0&&mG->edges[Col][i]==1)
            MG_DFSTraverse(mG,i);
}

void ALG_DFSTraverse(ALGraph* alG,int i)
{
    EdgeNode* p=alG->AdjList[i].firstedge;

    if (p==NULL)
        return ;

    alG->AdjList[i].visit=1;

    printf("vertex->%c\n",alG->AdjList[i].vertex);

    while (p=p->next)
        if (alG->AdjList[p->info].visit==0)
            ALG_DFSTraverse(alG,p->info);
}

/****************图的广度优先遍历 *******************/
void MG_BFSTraverse(MGraph* mG,EdgeType n)
{
    EdgeType queue[MaxVertexNum]={0};  //用队列来保存顶点信息
    EdgeType count[MaxVertexNum]={0};  //步长信息
    EdgeType step=1;                   //步长

    EdgeType front=0;   //队头指针
    EdgeType rear=0;    //队尾指针

    int Row=n;     

    printf("步长->%-3dvertex->%c\n",step,mG->vexs[Row]);

    queue[rear++]=Row;                 //第一个顶点入队
    count[rear-1]=step;

    mG->visit[Row]=1;                  //标记此顶点已经遍历

    while (front!=rear)                //当队列不为空时
    {
        if (count[front]==step)
            ++step;

        for (Row=0;Row<mG->n;++Row)
            if (mG->visit[Row]==0&&mG->edges[queue[front]][Row]==1)
            {
                printf("步长->%-3dvertex->%c\n",step,mG->vexs[Row]);
                queue[rear++]=Row;
                rear%=MaxVertexNum;

                assert(front!=rear+1);      //判断队满

                count[rear-1]=step;         //记录步长
                mG->visit[Row]=1;
            }

        ++front;
        front%=MaxVertexNum;
    }
}

void ALG_BFSTraverse(ALGraph* alG,int n)
{
    EdgeType queue[MaxVertexNum]={0};  //用队列来保存顶点信息
    EdgeType count[MaxVertexNum]={0};  //步长信息
    EdgeType step=1;                   //步长

    EdgeType front=0;   //队头指针
    EdgeType rear=0;    //队尾指针

    EdgeNode* p=alG->AdjList[n].firstedge;             

    printf("步长->%-3dvertex->%c\n",step,alG->AdjList[p->adjvex]);

    queue[rear++]=p->info;                //第一个顶点入队
    count[rear-1]=step;

    alG->AdjList[p->info].visit=1;        //标记此顶点已经遍历

    while (front!=rear)
    {
        if (count[front]==step)
            ++step;

        p=alG->AdjList[queue[front]].firstedge;

        while (p=p->next)
            if (alG->AdjList[p->info].visit==0)
            {
                printf("步长->%-3dvertex->%c\n",step,alG->AdjList[p->info].vertex);

                queue[rear++]=p->info;  //入队
                rear%=MaxVertexNum;

                assert(front!=rear+1);        //判断队满

                count[rear-1]=step;           //记录步长
                alG->AdjList[p->info].visit=1;
            }

        ++front;
        front%=MaxVertexNum;
    }
}
/****************************************辅助函数*************************************/

EdgeType Search(MGraph* mG,VertexType c)
{
    int i=0;
    for (i=0;i<mG->n;++i)
        if (mG->vexs[i]==c)
            return i;

    return -1;
}

void Empty_MG_Visit(MGraph* mG)
{
    int i=0;

    for (i=0;i<mG->n;++i)
        mG->visit[i]=0;
}


void Empty_ALG_Visit(ALGraph* alG)
{
    int i=0;

    for (i=0;i<alG->n;++i)
        alG->AdjList[i].visit=0;
}

/****************************************main函数*************************************/ 
int main()
{
    MGraph G={0};
    ALGraph alG={0};

    int point=0;
    VertexType sc=0;

    CreateMGraph(&G);

    printMGraph(&G);

    MGraphtoALGraph(&G,&alG);

    puts("邻接表示例如下:");
    printALGraph(&alG);

    //邻接矩阵深度优先搜索
    puts("\n图的深度优先搜索:");
    printf("请输入查找起点搜索名称:");
    scanf("%c%*c",&sc);

    point=Search(&G,sc);

    if (point!=-1)
    {
        puts("\n邻接矩阵的深度优先搜索结果:");
        MG_DFSTraverse(&G,point);

        puts("\n邻接表的深度优先搜索结果:");
        ALG_DFSTraverse(&alG,point);
    }
    else
        puts("找不到该顶点信息!");

    Empty_MG_Visit(&G);   //重置搜索状态
    Empty_ALG_Visit(&alG);


    puts("\n图的广度优先搜索:");
    printf("请输入查找起点搜索名称:");
    scanf("%c%*c",&sc);

    point=Search(&G,sc);

    if (point!=-1)
    {
        puts("\n邻接矩阵的广度优先搜索结果:");
        MG_BFSTraverse(&G,point);

        puts("\n邻接表的广度优先搜索结果:");
        ALG_BFSTraverse(&alG,point);
    } 
    else
        puts("找不到该顶点信息!");

    return 0;
} 


下一阶段就是要弄那个Dijkstra算法和Floyd算法~
看到网上大都是用邻接矩阵来弄~感觉邻接表的话代码会复杂很多~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-25 23:15
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
晚上通宵硬着头皮弄了个Dijkstra算法~感觉自己写得很复杂~~有很大优化空间~~不过还是弄出来了~我可没希望别人能够看懂我第一次弄的这个算法的代码~
里面两个枚举常量参考了数据结构与算法的这个贴~~不过里面的常量还有很多没有用到~
https://bbs.bccn.net/thread-475887-1-1.html

程序代码:
/*Dijkstra算法*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
#include<assert.h>

/*******************************宏定义*********************************************/

#define MaxVertexNum      20                 //图的最大顶点数
#define LEN              sizeof(Graph)       //图的容量
#define INF              -1                  //记录不连通状态

/*******************************自定义变量和全局变量*********************************************/

typedef enum 
{   
    UNDISCOVERED,
    DISCOVERED,
    VISITED

}VStatus;   //顶点状态
typedef enum 
{
    UNDETERMINED,
    TREE,
    CROSS,
    FORWARD,
    BACKWARD

}EStatus;  //边状态
         //上面两个枚举有很多常量暂时没什么用,先保留
typedef int EdgeType;   

typedef struct Min_Road
{
    EdgeType start;                   //最短路径的起点

    EdgeType min_dis[MaxVertexNum];   //最短路径到各点的距离
    EdgeType step[MaxVertexNum];      //最短路径的步长
    EdgeType path[MaxVertexNum][MaxVertexNum];      //最短路径信息

}Min_Road;

typedef struct Min_Status    //最短路径状态
{
    VStatus visit[MaxVertexNum];  //顶点状态
    EStatus edges[MaxVertexNum][MaxVertexNum];  //边状态

    Min_Road road;           //最短路径的距离(Floyd算法就用一维数组)
}Min_Status;

typedef struct Graph
{
    EdgeType n;   //顶点数
    EdgeType e;   //边数

    EStatus edges[MaxVertexNum][MaxVertexNum];  //边状态(判断是否连通)
    EdgeType dis[MaxVertexNum][MaxVertexNum];    //边的长度

    Min_Status status;    //最短路径状态结构体
    
}Graph,*PGraph;    

/*******************************函数申明部分*********************************************/

void Creat_Graph(PGraph* p);  //创建邻接矩阵
void Init_Graph(PGraph p);    //初始化邻接矩阵
void Print_Graph(PGraph p);   //输出邻接矩阵

void Dijkstra(PGraph p,EdgeType n);  //计算起点与各点之间的最短距离

void Print_Min_Path(PGraph p);  //输出最短路径

void Del_Graph(PGraph* p);    //释放邻接矩阵

/*******************************main()函数*********************************************/

int main()
{
    EdgeType o=0;
    PGraph g=NULL;

    Creat_Graph(&g);

    Init_Graph(g);       //初始化一张图

    Print_Graph(g);      //输出邻接矩阵

    puts("请输入原点:");

    assert(scanf("%d",&o)==1&&o<g->n&&o>-1);

    Dijkstra(g,o);       //Dijkstra算法

    Print_Min_Path(g);   //输出最短路径

    Del_Graph(&g);

    return 0;
}

/*******************************定义函数部分*********************************************/

void Creat_Graph(PGraph* p)
{
    *p=(PGraph)malloc(LEN);
    assert(*p);
    memset(*p,0,LEN);
}

void Del_Graph(PGraph* p)    //释放一张图
{
    if (*p==NULL)
        return ;

    free(*p);
    *p=NULL;
}

void Init_Graph(PGraph p)    //初始化一张图
{
    int n=0;
    int e=0;

    int i=0;
    int j=0;

    int from=0;   //从哪里来
    int to=0;     //到哪里去

    int dis=0;    //距离

    printf("请输入图的顶点数和边数(中间用空格隔开,最大顶点不能超过%d个):\n",MaxVertexNum);

    assert(scanf("%d%d",&n,&e)==2&&n<MaxVertexNum);

    p->n=n;
    p->e=e;

    for (i=0;i<p->n;++i)
    {
        p->status.visit[i]=UNDISCOVERED;   //初始化顶点为未收录状态

        for (j=0;j<p->n;++j)
        {
            p->status.edges[i][j]=UNDETERMINED;   //初始化遍历边为未处理状态

            if (i!=j)
            {
                p->edges[i][j]=UNDETERMINED;       //初始化为不连通状态
                p->dis[i][j]=INF; 
            }
            else
            {
                p->edges[i][j]=CROSS;
                p->dis[i][j]=0;
            }                    
        }
    }

    printf("请输入%d条边的连通状态和长度(每行输入两个顶点坐标和长度,中间用空格隔开):\n",p->e);

    for (i=0;i<p->e;++i)
    {
        assert(scanf("%d%d%d",&from,&to,&dis)==3&&from<MaxVertexNum&&to<MaxVertexNum);

        p->edges[from][to]=CROSS;   //表示该点连通
        p->edges[to][from]=CROSS;   
        
        p->dis[from][to]=dis;  //初始化边的长度
        p->dis[to][from]=dis;
    }
}

void Print_Graph(PGraph p)   //输出邻接矩阵
{
    int i=0;
    int j=0;

    puts("各边的状态如下(-1表示不连通):");
    for (i=0;i<p->n;++i)
    {
        for (j=0;j<p->n;++j)
                printf("%-5d",p->dis[i][j]);

        puts("");
    }
}

void Dijkstra(PGraph p,EdgeType v0)  //计算起点与各点之间的最短距离
{

    int i=0;
    int j=0;

    p->status.road.start=v0;

    for (i=0;i<p->n;++i)
    {
        p->status.road.min_dis[i]=p->dis[v0][i];   //记录该顶点到附近点之间的距离
        p->status.road.path[i][0]=i;

        if (p->edges[v0][i]==CROSS&&v0!=i)
        {
            p->status.road.step[i]=1;             //记录步长
            p->status.edges[v0][i]=CROSS;         //表示该点已经连通
        }
        else if (v0==i) 
            p->status.road.step[i]=0;             //原点到原点的步长为1
    }

    p->status.visit[v0]=VISITED;   //表示该顶点已被访问过

    for (i=1;i<p->n;++i)
    {
        EdgeType u=v0;

        int mindist=INT_MAX;

        for (j=0;j<p->n;++j)
            if (p->status.visit[j]==VISITED||p->status.road.min_dis[j]==INF)
                continue;
            else if (p->status.road.min_dis[j]<mindist)
            {
                mindist=p->status.road.min_dis[j];
                u=j;
            }

        p->status.visit[u]=VISITED;    //获取最小权值的前驱u

        for (j=0;j<p->n;++j)
            if (p->status.visit[j]==VISITED||p->edges[u][j]!=CROSS)
                continue;
            else if ( (p->status.road.min_dis[j]==INF)||(p->status.road.min_dis[u]+p->dis[u][j]<p->status.road.min_dis[j]) )
            {
                p->status.road.min_dis[j]=p->status.road.min_dis[u]+p->dis[u][j];

                memmove(p->status.road.path[j],p->status.road.path[u],sizeof(p->status.road.path[0]));

                p->status.road.step[j]=p->status.road.step[u]+1;
                p->status.road.path[j][p->status.road.step[j]-1]=j;
            }
    }
}

void Print_Min_Path(PGraph p)  //输出最短路径
{
    int i=0;
    int j=0;

    printf("顶点%d到各点的最短路径如下:\n",p->status.road.start);

    for (i=0;i<p->n;++i)
    {
        if (i==p->status.road.start)
            continue;
        
        if (p->status.road.min_dis[i]==INF)
        {
            printf("%d->%d没有找到路径!\n",p->status.road.start,i);
            continue;
        }

        printf("%d->%d的最短距离是:%-5d\n",p->status.road.start,i,p->status.road.min_dis[i]);
        printf("最短路径是:\n%d",p->status.road.start);
        for (j=0;j<p->status.road.step[i];++j)
            printf("->%-3d",p->status.road.path[i][j]);

        puts("\n");
    }

}

/******************************结尾*********************************************/


[此贴子已经被作者于2017-4-26 14:09编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-26 06:34
快速回复:分享图的邻接表深度和广度优先搜索~
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.033096 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved