图的结构
1、邻接矩阵结构
#define MAXSIZE 100
#define INFINITY 65535 //无穷大,表示两点直接没有路径连接
typedef struct Mgraph{
char vex[MAXSIZE]; //定义顶点数组
int arc[MAXSIZE][MAXSIZE]; //定义邻接矩阵
int numvex, numedge; //定义顶点个数和边的个数
};
无向矩阵的创建
void CreatMgraph(Mgraph *G){
int i, j, k, weight; //weight表示边上的权值
scanf("%d,%d", &G->numvex, &G->numedge); //读入顶点个数和边个数
for (i = 0; i < numvex; i++)
scanf("%c", &G->vex[i]); //读入顶点信息到数组中
for (i = 0; i < numvex; i++)
for (j = 0; j < numvex; j++)
G->arc[i][j] = INFINITY; //初始化邻接矩阵数组为无穷大
for (k = 0; k < numedge; k++){
scanf("%d,%d,%d", &i, &j, &weight); //读入边之间的路径(vi,vj)和权值
G->arc[i][j] = weight;
G->arc[j][i] = weight; //此处为无向图,因此矩阵的权值是对角对称结构。如果为有向图,则需要另考虑权值
}
}
2、邻接表的结构
typedef struct EdgeNode{
int adjvex; //邻接点对应的下标
int weight; //权值
struct EdgeNode *next;
};
typedef struct VexNode{ //顶点结点
int data; //顶点信息
struct EdgeNode *first; //头指针
};
typedef struct Graphlist{ //邻接表结构
VexNode adjlist[MAXSIZE];
int numvex, numedge; //顶点数和边数
};
无向图邻接表的创建
void CreatGraphlist(Graphlist *G){
int i, j, k,w;
scanf("%d,%d", &G->numvex, &G->numedge); //读入边和顶点的个数
for (i = 0; i < numvex; i++){
scanf("%c", &G->adjlist[i].data); //读入顶点信息
G->adjlist[i].first = nullptr; //初始化头指针
}
for (k = 0; k < numedge; k++){
scanf("%d,%d,%d", &i, &j, &w); //读入边(vi,vj)以及对应的权值
EdgeNode *e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = j;
e->weight = w;
e->next = G->adjlist[i].first;
G->adjlist[i].first = e; //此处用的是链表操作的头插法
}
}
还有十字链表、邻接多重链表、边集数组结构
关于图的遍历,主要为两种,深度优先遍历DFS和广度优先遍历BFS
广度优先遍历DFS--类似于树的前序遍历操作,
邻接矩阵的深度优先遍历
bool visited[MAX]; //使用一个标志数组来存储访问的信息
void DFS(MGraph G, int i){ //从第i个顶点开始遍历的DFS递归算法
int j;
visited[i] = true; //true表示该顶点被访问过
printf("%c", G.vex[i]);
for (j = 0; j <G.numvex; j++)
if (G.arc[i][j] != INFINITY &&!visited[j])
DFS(G, j);
}
void DFSTraverse(MGraph G){ //DFS遍历操作
int i;
for (i = 0; i <G.numvex; i++)
visited[i] = false; //初始化标志数组,表示所有顶点都未访问过
for (i = 0; i < G.numvex; i++)
if (!visited[i]) // 连通图的话,只执行一次,非连通图会至少两次
DFS(G, i);
}
邻接表的深度优先遍历
void DFS(Graphlist *G, int i){ //从第i个顶点开始遍历的DFS递归算法
EdgeNode *p; //相当于邻接矩阵中的j
visited[i] = true;
printf("%c", G->adjlist[i].data);
p = G->adjlist[i].first; //相当于j=0
while (p){
if (!visited[i])
DFS(G, p->adjvex);
p = p->next; //相当于j++
}
}
void DFSTraverse(Graphlist *G){ //DFS遍历操作
int i;
for (i = 0; i < G->numvex; i++)
visited[i] = false;
for (i = 0; i < G->numvex; i++)
if (!visited[i]) // 连通图的话,只执行一次,非连通图会至少两次
DFS(G, i);
}
广度优先遍历BFS --类似于树的层遍历方式,需要借助一个队列辅助来实现
队列Queue的操作在前面总结当中提过,不再重新定义,不过要注意,根据实际情况,队列当中的数据类型可能会是图 sturct MGraph类型或者struct Graphlist类型
邻接矩阵的广度遍历BFS
void BFSTraverse(MGraph G){
int i, j;
Queue Q; //辅助队列
for (i = 0; i < G.numvex; i++)
visited[i] = false;
InitQueue(&Q); //初始化队列
for (i = 0; i < G.numvex; i++){
if (!visited[i]){
visited[i] = true; // 连通图的话,只执行一次,非连通图会至少两次
printf("%c", G.vex[i]);
EnQueue(&Q, &i); //从第i个顶点开始BFS遍历
while (!QueueEmpty(Q)){ //队列不为空的时候继续遍历
Dequeue(&Q, &i);
for (j = 0; j < G.numvex; j++){
if (G.arc[i][j] != INFINITY && !visited){ //判断该顶点与其他顶点是否相连,并打印相连的顶点
visited[j] = true;
printf("%c", G.vex[j]);
Enqueue(&Q, &i); //将相邻的顶点存入队列中
}
}
}
}
}
}
邻接表的BFS
void BFSTraverse(Graphlist *G){
EdgeNode *p; //相当于邻接表中的j
int i;
Queue Q;
for (i = 0; i < G->numvex; i++)
visited[i] = false;
InitQueue(&Q);
for (i = 0; i < G->numvex; i++){
if (!visited[i]){
visited[i] = true; // 连通图的话,只执行一次,非连通图会至少两次
printf("%c", G->adjlist[i].data);
EnQueue(&Q, &i);
while (!QueueEmpty(Q)){ //队列不为空的时候继续遍历
DeQueue(&Q, &i);
p = G->adjlist[i].first; //相当于j=0
while (p){
if (!visited[p->adjvex]){
visited[p->adjvex] = true;
printf("%c", G->adjlist[p->adjvex].data);
Enqueue(&Q, &i);
}
p = p->next; //相当于j++
}
}
}
}
}