来看下面的一个简单的图,
那么这样的一个图,我们应该用什么存储结构来存储它呢?常用的是邻接矩阵和邻接表,这里邻接矩阵不做讲解,如下所有代码都是以邻接表作为存储结构,所以这里就只讲解下邻接表。那么什么是邻接表呢?如何构造呢?
邻接表是一种链式存储。就如上图,一共有四个顶点(分别是A,B,C,D),邻接表就是为这四个顶点的每个顶点建立一条单链表,也就是四条单链表,每个链表第一个元素就是该顶点自己。下面就以上面的图为例,具体介绍如何建立邻接表。
首先看第一条单链表,表头是顶点A。因为顶点A只与顶点B有邻接,因此,该单链表大概描述为A—->B;
再看第二条单链表,表头是B,而B与A,C,D都有邻接,故而描述为B—–>A——->C——->D;
依次第三条单链表为C——>B—–>D;
最后第四条单链表为D——>B—–>C。
代码:
#include <stdio.h>
#include <malloc.h>
#define MAX_SUM 1000
bool visited[MAX_SUM]= {false}; //设置标志数组
struct ArcNode
{
int adjvex; //该弧所指向的顶点的位置
ArcNode * next; //指向下一条弧的指针
};
typedef struct VNode
{
char vertex; //顶点信息
ArcNode * firstarc; //指向第一条依附该顶点的弧的指针
} AdjList[MAX_SUM];
struct ALGraph
{
AdjList adjList;
int vexNum; //图的顶点数
int arcNum; //图的弧数
};
typedef struct node
{
int data;
node *next;
} Node,*LinkQueueNode;
typedef struct
{
LinkQueueNode front; //队头指针
LinkQueueNode rear; //队尾指针
} LinkQueue;
bool InitQueue(LinkQueue *Q);//链队列初始化
bool EnterQueue(LinkQueue *Q,int x);//入队,将数据元素x插入到队列Q中
bool DeleteQueue(LinkQueue *Q,int *x);//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
bool IsEmpty(LinkQueue *Q);//判断链队列是否为空
void CreateGraph(ALGraph *graph);//创建图
void PrintGraph(ALGraph *graph);//打印图
void depth_first_search(ALGraph *graph,int v);//深度优先遍历
void breadth_first_search(ALGraph *graph);//广度优先遍历
int main(void)
{
/*
请输入图的顶点数:
4
请输入图的弧数:
4
请输入4个顶点信息:
ABCD
请输入4个弧的信息:
0 1
0 2
1 2
2 3
邻接表打印为:
A------>C B
B------>C A
C------>D B A
D------>C
深度优先搜索DFS:A C D B
广度优先搜索BFS:A C B D
*/
ALGraph graph;
CreateGraph(&graph);
printf("\n邻接表打印为:\n");
PrintGraph(&graph);
printf("\n深度优先搜索DFS:");
for (int i = 0; i < graph.vexNum; i++)
if (!visited[i])//如果没有访问
depth_first_search(&graph,i);
printf("\n");
printf("\n广度优先搜索BFS:");
breadth_first_search(&graph);
printf("\n");
return 0;
}
bool InitQueue(LinkQueue *Q)//链队列初始化
{
Q->front=(LinkQueueNode)malloc(sizeof(Node));
if(Q->front!=NULL)
{
Q->rear=Q->front;
Q->front->next=NULL;
return true;
}
else
return false;//溢出
}
bool EnterQueue(LinkQueue *Q,int x)//入队,将数据元素x插入到队列Q中
{
LinkQueueNode NewNode;
NewNode=(LinkQueueNode)malloc(sizeof(Node));
if(NewNode!=NULL)
{
NewNode->data=x;
NewNode->next=NULL;
Q->rear->next=NewNode;
Q->rear=NewNode;
}
else
return false;//溢出
}
bool DeleteQueue(LinkQueue *Q,int *x)//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
{
LinkQueueNode p;
if(Q->front==Q->rear)//表示队列已空
return false;
p=Q->front->next;
Q->front->next=p->next;//队头元素p出队
if(Q->rear==p)//如果队中只有一个元素p,则p出队后成为空队
Q->rear=Q->front;
*x=p->data;
free(p);//释放存储空间
return true;
}
bool IsEmpty(LinkQueue *Q)//判断链队列是否为空
{
return Q->front == Q->rear;
}
void CreateGraph(ALGraph *graph)//创建图
{
printf("请输入图的顶点数:\n");
scanf("%d",&graph->vexNum);
printf("请输入图的弧数:\n");
scanf("%d",&graph->arcNum);
getchar();
printf("请输入%d个顶点信息:\n",graph->vexNum);
for (int i = 0; i < graph->vexNum; i++)
{
scanf("%c",&graph->adjList[i].vertex);
graph->adjList[i].firstarc = NULL;
}
printf("请输入%d个弧的信息:\n",graph->arcNum);
int h1, h2;
ArcNode * temp;
for (int i = 0; i < graph->arcNum; i++)//根据输入的弧的信息构造邻接表
{
scanf("%d%d",&h1,&h2);
temp = new ArcNode;
temp->adjvex = h2;
temp->next = graph->adjList[h1].firstarc;
graph->adjList[h1].firstarc = temp;
temp = new ArcNode;
temp->adjvex = h1;
temp->next = graph->adjList[h2].firstarc;
graph->adjList[h2].firstarc = temp;
}
}
void PrintGraph(ALGraph *graph)//打印图
{
for (int i = 0; i < graph->vexNum; i++)
{
printf("%c------>",graph->adjList[i].vertex);
ArcNode *p = graph->adjList[i].firstarc;
while (p)
{
printf("%c ",graph->adjList[p->adjvex].vertex);
p = p->next;
}
printf("\n");
}
}
void depth_first_search(ALGraph *graph,int v)//深度优先遍历
{
visited[v] = true;
printf("%c ",graph->adjList[v].vertex);
ArcNode *p = graph->adjList[v].firstarc;
while (p)
{
if (!visited[p->adjvex])
depth_first_search(graph, p->adjvex);
p = p->next;
}
}
void breadth_first_search(ALGraph *graph)//广度优先遍历
{
for (int i = 0; i < MAX_SUM; i++)//初始化访问标志数组
visited[i] = false;
LinkQueue Queue;
int x;
InitQueue(&Queue);
for (int i = 0; i < graph->vexNum; i++)
if (!visited[i])//如果没有访问过
{
visited[i] = true;
EnterQueue(&Queue,i);//访问过的入队列
printf("%c ",graph->adjList[i].vertex);
while (!IsEmpty(&Queue))//队列不为空时
{
DeleteQueue(&Queue,&x);//先取出队首第一个元素,然后将第一个元素删除
ArcNode *p = graph->adjList[x].firstarc;
while(p)//访问未被访问过的邻接顶点
{
if (!visited[p->adjvex])
{
visited[p->adjvex] = true;
printf("%c ",graph->adjList[p->adjvex].vertex);
EnterQueue(&Queue,p->adjvex);
}
p = p->next;
}
}
}
}