图的算法

  1. 图的存储结构:

    (1)     邻接矩阵

1 typedef struct{
2     int no;//顶点编号
3     char data[MAXL];//顶点其他信息 
4 }VertexType;//顶点类型 
5 typedef struct{ 6 int edges[MAXV][MAXV];//边数组 7 int n,e;//顶点数、边数 8 VertexType vexs[MAXV];//存放顶点信息 9 }MGraph;//完整的图邻接矩阵类型

 

    (2)     邻接表

 1 typedef struct ANode{
 2     int adjvex;//终点编号 
 3     int weight;//权重 
 4     struct ANode *nextarc;//指向下一条边 
 5 }ArcNode;//边节点类型 
6 typedef struct Vnode{ 7 char data[MAXL];//顶点的其他信息 8 ArcNode *firstarc;//指向第一条边 9 }VNode;//表头结点类型
10 typedef struct{ 11 VNode adjlist[MAXV];//邻接表 12 int n,e;//顶点数、边数 13 }ALGraph; //完整的图邻接表类型

 

  1. 遍历:访问图中所有点仅一次,设置visited[MAXV]数组

    (1)     深度优先遍历DFS,递归回溯遍历所有顶点,常用于图的路径查找

 1 //基于递归的邻接矩阵的深搜 
 2 void DFS(MGraph g,int v){
 3     cout<<v<<" ";
 4     visited[v]=1;
 5     for(int i=0;i<g.n;i++){
 6         if(g.edges[v][i]!=0&&g.edges[v][i]!=INF&&visited[i]==0){
 7             DFS(g,i);
 8         }
 9     }
10 } 
11 
12 //基于递归的邻接表的深搜 
13 void DFS(ALGraph *g,int v){
14     cout<<v<<" ";
15     visited[v]=1;
16     ArcNode *p=g->adjlist[v].firstarc;
17     while(p!=NULL){
18         if(visited[p->adjvex]==0) DFS(g,p->adjvex);
19         p=p->nextarc;
20     }
21 }

 

    (2)     广度优先遍历BFS,需要使用先进先出的队列

 1 //使用队列的邻接矩阵的广搜
 2 void BFS(MGraph g,int v){
 3     queue<int> qu;
 4     cout<<v<<" ";
 5     visited[v]=1;
 6     qu.push(v);
 7     while(!qu.empty()){
 8         int w=qu.front();
 9         qu.pop();
10         for(int i=0;i<g.n;i++){
11             if(g.edges[w][i]!=0&&g.edges[w][i]!=INF&&visited[i]==0){
12                 cout<<i<<" ";
13                 visited[i]=1;
14                 qu.push(i);
15             }
16         }
17     }
18 } 

 

  1. 最小生成树

    (1)     Pirm算法:在两个顶点集之间选择权最小的边

 1 void Prim(MGraph g,int v){
 2     int lowcost[MAXV];//各点到U的最短距离
 3     int mincost;
 4     int closet[MAXV],i,j,k;//lowcost最短距离的上一个节点是 
 5     for(j=0;j<g.n;j++){
 6         lowcost[j]=g.edges[v][j];
 7         closet[j]=v;
 8     } 
 9     for(i=1;i<g.n;i++){
10         mincost=INF;
11         for(j=0;j<g.n;j++){
12             if(lowcost[j]!=0&&mincost<lowcost[j]){
13                 mincost=lowcost[j];
14                 k=j;
15             }
16         }
17         cout<<closet[k]<<""<<k<<"权为"<<mincost<<endl;
18         lowcost[k]=0;
19         for(j=0;j<g.n;j++){
20             if(lowcost[j]>g.edges[k][j]&&g.edges[k][j]!=0){
21                 lowcost[j]=g.edges[k][j];
22                 closet[j]=k;
23             }
24         }
25     } 
26 } 

 

    (2)     Kruskal算法:按边权值从小到大,如果未使生成树形成回路则加入,关键是判断是否是回路    (并查集)

    *并查集以及并查集的优化

  1. 最短路径

    (1)     Dijkstra算法(单源最短路径):

 1 void Dijkstra(MGraph g,int v){
 2     int dist[MAXV],path[MAXV];
 3     int S[MAXV];
 4     int min,i,j,u;
 5     //初始化
 6     for(i=0;i<g.n;i++){
 7         dist[i]=g.edges[v][i];
 8         S[i]=0;
 9         if(g.edges[v][i]<INF) path[i]=v;
10         else path[i]=-1;
11     } 
12     S[v]=1;path[v]=0;
13     //求最短路径 
14     for(i=0;i<g.n;i++){
15         min=INF;
16         //找到目前最小 
17         for(j=0;j<g.n;j++){
18             if(min>dist[j]&&S[j]==0){
19                 min=dist[j];
20                 u=j;
21             }
22         }
23         S[u]=1;
24         //看看新的点能否使更小 
25         for(j=0;j<g.n;j++){
26             if(g.edges[u][j]+dist[u]<dist[j]&&g.edges[u][j]<INF){
27                 dist[j]=g.edges[u][j]+dist[u];
28                 path[j]=u;
29             }
30         }
31     }
32 } 

 

    (2)     Bellman-Ford算法(单源最短路径、允许存在负边):n-1次松弛,可以用来判断是否存在负回路

 1 void BellmanFord(MGraph g,int v){
 2     int i,k,u;
 3     int dist[MAXV],path[MAXV];
 4     for(i=0;i<g.n;i++){
 5         dist[i]=g.edges[v][i];
 6         if(i!=v&&dist[i]<INF)path[i]=v;
 7         else path[i]=-1;
 8     }
 9     for(k=1;k<g.n;k++){//dist\path数组的变化次 
10         for(u=0;u<g.n;u++){
11             if(u!=v){
12                 for(i=0;i<g.n;i++){
13                     if(g.edges[i][u]<INF&&dist[u]>dist[i]+g.edges[i][u]){
14                         dist[u]=dist[i]+g.edges[i][u];
15                         path[u]=i;
16                     }
17                 }
18             }
19         }
20     }
21 } 

 

    (3)     SPFA算法(单源最短路径、允许存在负边但不负权回路):需要用到图的邻接表

 1 void SPFA(ALGraph *g,int s){
 2     int dist[MAXV],path[MAXV],visited[MAXV];
 3     int v,w;
 4     ArcNode *p;
 5     queue<int> qu;
 6     for(int i=0;i<g->n;i++){
 7         dist[i]=INF;
 8         visited[i]=0;
 9         path[i]=-1;
10     }
11     dist[s]=0;
12     visited[s]=1;
13     qu.push(s);
14     while(!qu.empty()){
15         v=qu.front();
16         qu.pop();
17         visited[v]=0;
18         p=g->adjlist[v].firstarc;
19         while(p!=NULL){
20             w=p->adjvex;
21             if(dist[w]>dist[v]+p->weight){
22                 dist[w]=dist[v]+p->weight;
23                 path[w]=v;
24                 if(visited[w]==0){
25                     qu.push(w);
26                     visited[w]=1;
27                 }
28             }
29             p=p->nextarc;
30         }
31     }
32 } 

 

    (4)     Floyd算法(多源最短路径):dp

 1 void floyd(MGraph g){
 2     int a[MAXV][MAXV],path[MAXV][MAXV];
 3     int i,j,k;
 4     for(i=0;i<g.n;i++){
 5         for(j=0;j<g.n;j++){
 6             a[i][j]=g.edges[i][j];
 7             if(i!=j && g.edges[i][j]<INF) path[i][j]=i;
 8             else path[i][j]=-1;
 9         }
10     }
11     for(k=0;k<g.n;k++){
12         for(i=0;i<g.n;i++){
13             for(j=0;j<g.n;j++){
14                 if(a[i][j]>a[i][k]+a[k][j]){
15                     a[i][j]=a[i][k]+a[k][j];
16                     path[i][j]=path[k][j];
17                 }
18             }
19         }
20     }
21 }

 

posted @ 2023-05-24 11:36  gfygfy  阅读(31)  评论(0)    收藏  举报