设计并验证如下算法:带权图采用邻接表表示,实现有向图的广度优先搜索与无向图的深度优先搜索。
#define MAX_VERTEX_NUM 20 //图的邻接表存储表示
typedef struct ArcNode{
int adjvex; //该弧所指向的顶点的位置
struct ArcNode *nextarc; //指向下一条弧的指针
InfoType *info; //该弧相关信息的指针
}ArcNode;
typedef struct VNode {
VertexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];
Typedef struct {
AdjList vertices;
int vexnum,arcnum; //图的当前顶点数和弧数
int kind; //图的种类标志
}ALGraph;
//
// Created by CHAO on 2021-12-13.
//
//设计并验证如下算法:带权图采用邻接表表示,实现有向图的广度优先搜索与无向图的深度优先搜索
#define MAX_VERTEX_NUM 20 //图的邻接表存储表示
#include "stdio.h"
#include "stdlib.h"
typedef char VertexType;
//链表结点
typedef struct ArcNode{
int adjvex; //下标
int power;
struct ArcNode *next; //下一个
}ArcNode;
typedef struct node{
int date;
struct node *next;
}Node ;
//图结点
typedef struct VNode {
VertexType data; //顶点信息
ArcNode *firstarc; //指向第一条依附该顶点弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];
//整个图的
typedef struct {
AdjList vertices; //20个图结点
int vexnum,arcnum; //图的顶点数和边的个数
int kind; //图的种类标志
}ALGraph;
void create(ALGraph *G){ //创建图
printf("输入顶点数和边数以及图的类型(1为有向,2为无向 ):\n");
scanf("%d%d%d",&G->vexnum,&G->arcnum,&G->kind);
//创建顶点
printf("输入顶点信息:\n");
for(int i=0;i<G->vexnum;i++){
getchar();
scanf("%c",&G->vertices[i].data);
G->vertices[i].firstarc=(ArcNode *) malloc(sizeof (ArcNode));
G->vertices[i].firstarc->next=NULL; //将指向边表的指针初始化
}
//创建边
int i,j,pow;
printf("输入边的下标(用空格隔开)以及权值:\n");
for(int k=0;k<G->arcnum;k++){
scanf("%d%d%d",&i,&j,&pow);
ArcNode *p;
p=(ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
//存储弧头
p->power = pow; //权值
if (G->vertices[i].firstarc->next == NULL) { //第一个为空时,直接放
G->vertices[i].firstarc->next = p;
p->next = NULL;
} else {
ArcNode *q; //第一个不为空时,接在最后一个的后面
q = G->vertices[i].firstarc;
while (q->next != NULL)
q = q->next;
q->next = p;
p->next = NULL;
}
//当为无向图时,双方建立联系
if(G->kind==2){
p=(ArcNode *)malloc(sizeof(ArcNode));
p->adjvex=i;
p->power=pow;
if (G->vertices[j].firstarc->next == NULL) { //第一个为空时,直接放
G->vertices[j].firstarc->next = p;
p->next = NULL;
} else {
ArcNode *q; //第一个不为空时,接在最后一个的后面
q = G->vertices[j].firstarc;
while (q->next != NULL)
q = q->next;
q->next = p;
p->next = NULL;
}
}
}
}
void printfgraph(ALGraph G) //打印图
{
ArcNode *p;
for(int i=0;i<G.vexnum;i++){
p=G.vertices[i].firstarc->next;
while(p){
printf("(%c,%c)--power %d ",G.vertices[i].data,G.vertices[p->adjvex].data,p->power);
p=p->next;
}
printf("\n");
}
}
void enquene(Node *Q,Node *p){ //进队列
Node *q=Q;
if( Q->next==NULL) {
Q->next = p;
p->next=NULL;
}
else
{
while(q->next!=NULL)
q=q->next;
q->next=p;
p->next=NULL;
}
}
Node dequene(Node *Q){ //出队列
Node p;
if(Q->next==NULL) {
printf("队列中无元素\n");
exit(0);
}
else if(Q->next->next==NULL) {
p=* (Q->next);
Q->next=NULL;
}
else
{
Node *ss=Q->next->next;
p=*(Q->next);
Q->next=ss;
}
return p;
}
int queneEmpty(Node *Q){ //判读队列是否为空
if(Q->next==NULL)
return 1;
else
return 0;
}
void BFS(ALGraph gragh,Node *v){ //广度优先遍历
int visit[MAX_VERTEX_NUM];
for(int i=0;i<gragh.vexnum;i++)
visit[i]=0;
Node *quene=(Node*)malloc(sizeof(Node));
quene->next=NULL;
enquene(quene,v);
printf("%c ",gragh.vertices[v->date].data);
visit[v->date]=1;
while(!queneEmpty(quene))
{
Node p;
p=dequene(quene); //出
ArcNode *xi;
xi=gragh.vertices[p.date].firstarc->next;
while(xi)
{
Node *t=(Node *)malloc(sizeof (Node));
t->date=xi->adjvex;
if(visit[t->date]!=1) {
enquene(quene,t);
printf("%c ",gragh.vertices[t->date].data);
visit[t->date]=1;
}
xi=xi->next;
}
}
}
void dFS(ALGraph *G,int v,int *visit){ //深度优先
ArcNode *p;
printf("%c ",G->vertices[v].data);
visit[v]=1;
p=G->vertices[v].firstarc->next;
while (p){
if(visit[p->adjvex]==0){
dFS(G,p->adjvex,visit);
}
p=p->next;
}
}
void DFS(ALGraph *g){ //非连通情况
int i;
int visit[100]={0};
for(i=0;i<g->vexnum;i++){
if(visit[i]==0){
dFS(g,i,visit);
}
}
}
int main(){
ALGraph G;
int visit[MAX_VERTEX_NUM]={0};
create(&G);
printf("图建立完毕\n");
printfgraph(G);
Node TT;
TT.date=0;
printf("广度遍历:\n");
BFS(G,&TT); //广度遍历
printf("\n深度遍历:\n");
dFS(&G,0,visit); //深度优先
return 0;
}
1.先输入图的顶点数目,边的数目,以及图的类型,(1代表有向图,2,代表无向图。)后输入边以及权值,用顶点的下标代替边的弧头弧尾。下面给出一组输入:
4 4 1
A B C D
0 1 5
0 2 7
0 3 9
1 2 12
2.图创建完成后会先普通输出一下,以此判断是否建立正确,所以会输出边和权值, 广度深度遍历,深度遍历都只是输出顶点数据。
3. 深度优先遍历时用到递归的方式,但是当出现一个或者两个单独结点时,就会出现遍历不到的情况,所以我用到了一个循环,循环遍历图的结点数据。