本文主要记录了C语言实现的几个图这一章需要重点掌握并且体会的算法。实现的结构另参照其他文章。
算法基本参照了书上的伪代码和http://www.cnblogs.com/kangjianwei101/category/791617.html
算法列表目录:
1.图的深度优先搜索 DFS
2.图的广度优先搜索 BFS
3.无向图的连通分量/生成树
4.有向图的强连通分量/生成树 (SCC) Kosaraju算法
5.无向网的最小生成树 Prim 算法 和 Kruskal算法(技术不够...未实现)
6.无向图的关节点 (DFS算法的改进)
7.有向无环图的拓扑排序 (+对是否有环的判断)
8.有向网的关键路径 (依赖拓扑序列的实现)
9.有向网的最短路径 Dijkstra 算法和 Floyd算法
说明:基本上无特殊注释的数组0号单元均未弃用
算法实现:
1.图的深度优先搜索 DFS
算法依赖于实现寻找弧/边和下一条弧/边的函数FirstAdjVex,NextAdjVex。输入与返回均为顶点值
Status DFSTraverse (ALGraph G, Status(*Visit)(VertexType))
{
int v;
VisitFunc = Visit;
for (v=0;v<G.vexnum;v++){
visited[v] = -1;
}
pre = 0;
for (v=0;v<G.vexnum;v++){
if(visited[v]==-1)
DFS(G,v);
}
return OK;
}
Status DFS (ALGraph G,int v)
{
int w;
if (VisitFunc(G.vertices[v].data)==ERROR)
return ERROR;
visited[v] = pre;
pre = v;
for (w = FirstAdjVex(G,G.vertices[v].data);w>=0;w = NextAdjVex(G,G.vertices[v].data,G.vertices[w].data)){
if (visited[w]==-1)
DFS(G,w);
}
return OK;
} //开始每一次遍历的序号
2.图的广度优先搜索 BFS
BFS同样依赖于FirstAdjVex,NextAdjVex函数,以及队列这个数据结构。
Status BFSTraverse (ALGraph G, Status(*Visit)(VertexType))
{
int v,w;
LinkQueue Q;
InitQueue(&Q);
QElemType e;
for (v=0;v<G.vexnum;v++){
visited[v] = -1;
}
pre = 0;
for (v=0;v<G.vexnum;v++){
if (visited[v]==-1){
visited[v] = pre;
Visit(G.vertices[v].data);
EnQueue(&Q,v);
while (!QueueEmpty(Q)){
DeQueue(&Q,&e);
for (w= FirstAdjVex(G,G.vertices[e].data);w>=0;w=NextAdjVex(G,G.vertices[e].data,G.vertices[w].data)){
if (visited[w]==-1){
Visit(G.vertices[w].data);
visited[w] = pre;
pre = w;
EnQueue(&Q,w);
}
}
}
}
}
return OK;
}
3.无向图的连通分量/生成树
生成树的存储方法为Left Child-Right Sibling二叉树。本质是DFS遍历顶点。算法利用DFS核心函数的特性,跳出一次核心函数代表着创建出了一棵生成树,树的结点构成了图的连通分量。
#ifndef SPANNINGTREE_H
#define SPANNINGTREE_H
#include <stdio.h>
#include <stdlib.h>
#include "MGraph.h"
#include "ChildSibling.h"
//无向图生成树函数列表
void DFSForest (MGraph G, CSTree *T);
//创建无向图的生成树
void DFSTree (MGraph G,int v,CSTree *T);
//生成结点v起始的树
#endif // SPANNINGTREE_H
#ifndef SPANNINGTREE_C
#define SPANNINGTREE_C
#include "SpanningTree.h"
//无向图生成树函数列表
void DFSForest (MGraph G, CSTree *T)
{ //建立无向图G的深度优先生成森林的最左孩子右兄弟生成链表T
InitTree_CS(T);
int v; //用来遍历
for (v=0;v<G.vexnum;v++){
visited[v] = FALSE;
}
CSTree p,q; //p为新的根节点,q为上一个根节点
for (v=0;v<G.vexnum;v++){
if (!visited[v]){
//新的树生成根节点
p = (CSTree)malloc(sizeof(CSNode));
if (!p)
exit (OVERFLOW);
p->data = GetVex_M(G,v);
p->firstchild = p->nextsibling = NULL;
if(TreeEmpty_CS(*T))
*T = p; //第一棵生成树的根
else
q->nextsibling = p;
q = p;
DFSTree(G,v,&p);
}
}
}
//创建无向图的生成树
void DFSTree (MGraph G,int v,CSTree *T)
{
//从顶点序号v出发深度优先遍历图G,建立以T为根的生成树
Status first;
int w;
CSTree p,q;
visited[v] = TRUE;
first = TRUE;
for (w=FirstAdjVex_M(G,G.vexs[v]);w>=0;w=NextAdjVex_M(G,G.vexs[v],G.vexs[w])){
if (!visited[w]){
//分配孩子结点
p = (CSTree)malloc(sizeof(CSNode));
if (!p)
exit(OVERFLOW);
p->data = GetVex_M(G,w);
p->firstchild = p->nextsibling = NULL;
if (first){
(*T)->firstchild = p;
first = FALSE;
} else
q->nextsibling = p;
q = p;
DFSTree(G,w,&q);
}
}
}
//生成结点v起始的树
#endif // SPANNINGTREE_C
4.有向图的强连通分量/生成树 (SCC) Kosaraju算法
生成树的存储方法为Left Child-Right Sibling二叉树。
其中finished[]数组最为精髓。它用来记录正常深度搜索跳出DFS核心函数的顶点序号。
然后逆置有向图。再从finished[]数组的最后一个顶点出发,对逆向图进行DFStraverese。此时每调用一次DFS函数访问到的顶点集便是有向图的一个强连通分量SCC所构成的顶点集。
#ifndef SCC_H
#define SCC_H
//利用十字链表存储的有向图求强连通分量
//Kosaraju算法
#include <stdio.h>
#include "OLGraph.h"
#include "ChildSibling.h"
//全局变量
int counts;
int finished [MAX_VERTEX_NUM];
//求强连通分量的函数列表
void InverseGraph (OLGraph *G);
//逆制有向图
void DFSTraverse_SCC (OLGraph G);
//改动后的深度优先遍历
void DFS_SCC1(OLGraph G, int v);
void DFS_SCC2(OLGraph G, int v);
void Kosaraju (OLGraph G);
//有向图的强连通分量的kosaraju算法
void KosarajuForest(OLGraph G, CSTree* T);
void KosarajuTree (OLGraph G,int v,CSTree *T);
#endif // SCC_H
#ifndef SCC_C
#define SCC_C
#include "SCC.h"
全局变量
//int counts;
//int finished [MAX_VERTEX_NUM];
void InverseGraph (OLGraph *G)
{
int i; //i用来遍历顶点
VexNode *h; //用来遍历顶点
ArcBox *tmp,*p,*q; //p用来遍历弧
int k;//用来交换顶点序号
for (i=0;i<G->vexnum;i++){
h = &(G->xlist[i]);
if (h->firstout)
p = h->firstout;
//交换第一条入弧和出弧
tmp = h->firstout;
h->firstout = h->firstin;
h->firstin = tmp;
//交换每条弧
while (p){
q = p;
p = p->tlink;
k = q->tailvex;
q->tailvex = q->headvex;
q->headvex = k;
tmp = q->tlink;
q->tlink = q->hlink;
q->hlink = tmp;
}
}
}
//逆制有向图
vo