图的算法
- 图的存储结构:
(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; //完整的图邻接表类型
- 遍历:访问图中所有点仅一次,设置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) 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) 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 }

浙公网安备 33010602011771号