图的存储结构
邻接矩阵
定义:邻接矩阵是表示顶点之间相邻关系的矩阵。设G = (V,E)是具有n个顶点的图,顶点序号依次为0,1,2,…,n-1,则G的邻接矩阵是具有如下定义的n阶方阵A:
A[i][j] = 1表示顶点i与j邻接,即i与j之间存在边或者弧
A[i][j] = 0表示顶点i与j不邻接(0<=i,j<=n-1)邻接矩阵结构的定义
#define MaxVertexNum 100 /*最大顶点数设为100*/
typedef char VertexType; /*顶点类型设为字符型*/
typedef int EdgeType; /*无权图用0或1表示顶点是否邻接,网则表示权值*/
typedef struct {
VertexType vexs[MaxVertexNum]; /*顶点表*/
EdeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵*/
int n,e; /*顶点数和边数*/
}Mgragh; /*Maragh 是以邻接矩阵存储的图类型*/
建立一个图的邻接矩阵存储的算法如下:
void CreateMGraph(MGraph *G)
{
/*建立有向图G 的邻接矩阵存储*/
int i,j,k,w;
char ch;
printf("请输入顶点数和边数(输入格式为:顶点数,边数):\n");
/*输入顶点数和边数*/
scanf("%d,%d",&(G->n),&(G->e));
/*输入顶点信息,建立顶点表*/
printf("请输入顶点信息:\n");
for (i = 0; i < G->n; i++)
scanf("\n%c",&(G->vexs[i]));
/*初始化邻接矩阵*/
for (i = 0;i < G->n; i++)
for (j = 0; j<G->n; j++)
G->edges[i][j]=0;
printf("请输入每条边对应的两个顶点的序号(输入格式为:i,j):\n");
for (k=0;k<G->e;k++)
{
scanf("\n%d,%d",&i,&j); /*输入e 条边,建立邻接矩阵*/
G->edges[i][j]=1;
/*若加入G->edges[j][i]=1;*/
/*则为无向图的邻接矩阵存储建立*/
}
}
邻接表
定义:邻接表(Adjacency List)是图的一种顺序存储与链式存储结合的存储方法。邻接表表示法类似于树的孩子链表表示法。就是对于图G 中的每个顶点vi,将所有邻接于vi 的顶点vj 链成一个单链表,这个单链表就称为顶点vi 的邻接表,再将所有点的邻接表表头放到数组中,就构成了图的邻接表。在邻接表表示中有两种结点结构,如图所示:
一种是顶点表的结点结构,它由顶点域(vertex)和指向第一条邻接边的指针域(firstedge)构成,另一种是边表(即邻接表)结点,它由邻接点域(adjvex)和指向下一条邻接边的指针域(next)构成。对于网图的边表需再增设一个存储边上信息(如权值等)的域(info),网图的边表结构如图所示
邻接表的定义:
#define MAX_VERTEX_NUM 100
typedef int VertexType;
typedef struct node{
int adjvex;
struct node * next;
int info; /*We can add an info node to represent weight*/
}EdgeNode;
typedef struct vnode{
VertexType vertex;
EdgeNode * firstedge;
}VertexNode;
/*This is a weird express way,what it expected to show may like Java:VertexNode[MAX_VERTEX_NUM] AdjList*/
typedef VertexNode AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList adjlist;
int n, e;
}AdjGraph;
- 图的遍历
DFS
//define global variable
bool visited[MAX_VERTEX_NUM]; /*mark if the vertex has visited*/
int dfn[MAX_VERTEX_NUM]; /*record the DFS sequence num*/;
int cnt = 1; /* counter */
void DFSTraverse(Graph * G)
{
for (int i = 0; i < G->n; ++i)
visited[i] = false;
for (int i = 0; i < G->n; ++i)
if (!visited[i])
DFS(G,i);
}
/*邻接表DFS*/
void DFS(AdjGraph * G, int i)
{
EdgeNode * p;
cout << G->adjlist[i].vertex << endl;
visited[i] = true;
dfn[i] = cnt ++;
p = G->adjlist[i].firstedge;
while (p != NULL)
{
if (!visited[p->adjvex])
DFS(G,p->adjvex);
p = p->next;
}
}
/*邻接矩阵DFS*/
void DFS(MGraph * G, int i)
{
cout << G->vex[i] << endl;
visited[i] = true;
dfn[i] = cnt ++; /*可以不写这句*/
for (int j = 0; j < G->n; ++j)
if ((G->edge[i][j] == 1) && (!visited[j]))
DFS(G,j);
}
/* A general method */
void DFS(Graph * G, int i)
{
int w;
cout << i << endl;
visited[i] = true;
dfn[i] = cnt ++;
w = FirstAdjVertex(G,i);
while (w != NULL)
{
if (!visited[w])
DFS(G,w);
w = NextAdjVertex(G,i,w);
}
}
/*邻接表BFS*/
void
BFS(AdjGraph * G, int k)
{
int i;
Edge *p;
Queue Q;
InitQueue(Q);
cout << G->adjlist[k].vertex << endl;
visited[k] = true;
EnQueue(Q,k);
while (!IsEmpty(Q))
{
i = DeQueue(Q);
p = G->adjlist[i].firstedge;
while (p != NULL)
{
if (!visited[p->adjvex])
{
visited[p->adjvex] = true;
cout << G->adjlist[p->adjvex].vertex << endl;
EnQueue(Q,k);
}
p = p->next;
}
}
}
/*邻接矩阵BFS*/
void
BFS(MGraph * G, int k)
{
int i;
Queue Q;
InitQueue(Q);
cout << G->vex[k] << endl;
visited[k] = true;
EnQueue(Q,k);
while(!IsEmpty(Q))
{
i = DeQueue(Q);
for (int j = 0; j < G->n; ++j)
if (G->edge[i][j] == 1 && !visited[j])
{
visited[j] = true;
EnQueue(Q,j);
cout << G->vex[j] << endl;
}
}
}
最小生成树
- Prime算法
void prime(MGraph * G, int v0)
{
int min;
int lowcost[MAX_VERTEX_SIZE];
int vset[MAX_VERTEX_SIZE];
int sum = 0; //sum up the total weight
int k,v;
for (int i = 0; i < G->n; ++i)
{
lowcost[i] = G->edges[v0][i];
vset[i] = 0;
}
vset[v0] = 1;
for (int i = 0; i < G->n - 1; ++i)
{
min = INF //INF是定义好的一个比图中任何一条边的权值都大的数 for (int j = 0; j < G->n; ++j)
if (vset[j] == 0 && min > lowcost[j])
{
min = lowcost[j];
k = j;
}
vset[k] = 1;
v = k;
cout << min << " ";
sum += min;
for (int j = 0; j < G->n; ++j)
{
if (vset[j] == 0 && lowcost[j] > G->edges[v][j])
lowcost[j] = G->edges[v][j];
}
}
}
最短路径
有向无环图及其应用
一个有向的无环图称为有向无环图(Directed Acycline Graph),简称DAG.是比有向树更一般的特殊有向图。
拓扑排序(Topological Sort)
拓扑排序是将某个集合上的偏序得到这个集合全序的过程。
PS:有关偏序和全序的知识
或者,有如下定义:
拓扑排序其实就是对一个有向图构造拓扑序列的过程。- AOV-网(Activity On Vertex Network)
AOV网是一种以顶点表示活动,以边表示活动先后次序或制约关系的有向无环图。
求拓扑排序的思路:选取图中入度为0的顶点输出并删除,同时删除从该顶点发出的边。重复以上步骤直至图中没有入度为0的点。
我们采用邻接表的结构来描述这个过程,我们把邻接表的定义稍作修改。
typedef struct node{
int adjvex;
struct node * next;
int weight;
}EdgeNode;
typedef struct vnode{
int in;
VertexType vertex;
EdgeNode * firstedge;
}VertexNode;
int TopoSort(AdjGraph * G)
{
int cnt = 0;
int temp;
int stack[MAX_VERTEX_SIZE];
int top = -1;
EdgeNode * p;
for (int i = 0; i < G->n; ++i)
if (G->adjlist[i].in == 0)
stack[++top] = i;
while (top != -1)
{
temp = stack[top--];
cnt ++;
cout << temp << " ";
p = G->adjlist[temp].firstedge;
while (p)
{
(G->adjlist[p->adjvex].in)--;
if (G->adjlist[p->adjvex].in == 0)
stack[++top] = p->adjvex;
p = p->next;
}
}
if (cnt == G->n)
return 1;
return 0;
}
这里写代码片