邻接表是图的一种链式存储结构。在邻接表中,对每个顶点vi 建立一个单链表,把与vi有关联的边的信息链接起来,每个结点设为3个域;
//边结点的类型定义
typedef struct ArcNode{
int adjvex;//存放邻接的点在顶点表的下标,邻接点
struct ArcNode *next;//指向Vi下一个邻接点的边结点
}ArcNode;
//顶点结点类型定义
typedef struct vexnode
{
ver data; //存储顶点的名称或其相关信息
ArcNode *firstedge;//边表头指针
}vexnode;
//图的邻接表数据类型
typedef struct{
vexnode adjlist[maxsize];//顶点表
int vex,edge;
}graph;
创建图:
void creategraph(graph *g){
int i,j,k;
ver v1,v2;
ArcNode *s;
printf("顶点数 vex=");
scanf("%d",&g->vex);
printf("边 数 edge=");
scanf("%d",&g->edge);
printf("请输入图的顶点信息:\n");
getchar();
for(i=0;i<=g->vex;i++){
scanf("%c",&g->adjlist[i].data); //构造顶点信息
g->adjlist[i].firstedge=NULL;
}
for(k=0;k<g->edge;k++)
{
printf("请输入第%d条边的两个端点下标:",k+1);
scanf("%c %c",&v1,&v2);
getchar();//输入一条边的两个顶点
i=locatevex(*g,v1);
j=locatevex(*g,v2);
if(i>=0&&j>=0){
//建立无向图的邻接表
/*s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=j;
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=i;
s->next=g->adjlist[j].firstedge;
g->adjlist[j].firstedge=s;*/
//建立有向图的邻接表
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=j;
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;
}
}
}
DFS算法:
void DFS(graph g,int i)
{
ArcNode *p;
printf("%3c",g.adjlist[i].data);/*访问第i个项点*/
visited[i]=1;
p=g.adjlist[i].firstedge;
while(p!=NULL) {
if(visited[p->adjvex]==0)
DFS(g,p->adjvex);/*对i的尚未访问的邻接顶点j递归调用DFS*/
p=p->next;
}
}
void DFStraverse(graph g) /*对图G进行深度优先遍历*/
{
int v;
for (v=0; v<g.vex;v++)visited[v]=0; /*初始化标志数组*/
for (v=0; v<g.vex;v++) /*保证非连通图的遍历*/
/*从第v个顶点出发递归地深度优先遍历图G*/
if (!visited[v])DFS(g,v);
}
BFS算法:
void BFS(graph g,int k){
int i;
ArcNode *p;
initqueue(&q);/*初始化队列*/
printf("%3c",g.adjlist[k].data);/*访问第k个项点*/
visited[k]=1;
enqueue(&q,k);/*第k个顶点进队*/
while(queueempty(q)==0) {/*队列非空*/
dequeue(&q,&i);
p=g.adjlist[i].firstedge;/*获取第1个邻接点*/
while(p!=NULL){
if(visited[p->adjvex]==0){
/*访问第i个顶点的末曾访问的顶点*/
printf("%3c",g.adjlist[p->adjvex].data);
visited[p->adjvex]=1;
enqueue(&q,p->adjvex);/*第k个顶点进队*/
}
p=p->next;
}
}
}
void BFStraverse(graph g) //对图G进行广度优先遍历
{
int v;
for (v=0; v<g.vex;v++) //初始化标志数组
visited[v]=0;
for (v=0; v<g.vex;v++) //保证非连通图的遍历
if (!visited[v])BFS(g,v);
//从第v个顶点出发递归地深度优先遍历图G
}
在上述代码的过程中需要用到一些栈和循环队列的知识,详细知识请看完整代码。
完整代码如下:
/*C语言建立有向图的邻接表及其遍历*/
#include<stdio.h>
#include<stdlib.h>
//图的邻接矩阵储存结构
typedef char ver;
#define maxsize 10
#define queuesize 100
//边结点的类型定义
typedef struct ArcNode{
int adjvex;//存放邻接的点在顶点表的下标,邻接点
struct ArcNode *next;//指向Vi下一个邻接点的边结点
}ArcNode;
//顶点结点类型定义
typedef struct vexnode
{
ver data; //存储顶点的名称或其相关信息
ArcNode *firstedge;//边表头指针
}vexnode;
//图的邻接表数据类型
typedef struct{
vexnode adjlist[maxsize];//顶点表
int vex,edge;
}graph;
//在图g中查找顶点v,存在顶点数组中的下标,不存在返回0
int locatevex(graph g,ver v)
{
int i;
for(i=0;i<g.vex;i++)
if(g.adjlist[i].data==v)return i;
return 0;
}
//打印图信息
void print(graph g)
{
int i;
ArcNode *p;
printf("图的邻接表表示:");
for(i=0;i<g.vex;i++){
printf("\n%4c",g.adjlist[i].data);
p=g.adjlist[i].firstedge;
while(p!=NULL){
printf("-->%d",p->adjvex);
p=p->next;
}
}
printf("\n");
}
void creategraph(graph *g){
int i,j,k;
ver v1,v2;
ArcNode *s;
printf("顶点数 vex=");
scanf("%d",&g->vex);
printf("边 数 edge=");
scanf("%d",&g->edge);
printf("请输入图的顶点信息:\n");
getchar();
for(i=0;i<=g->vex;i++){
scanf("%c",&g->adjlist[i].data); //构造顶点信息
g->adjlist[i].firstedge=NULL;
}
for(k=0;k<g->edge;k++)
{
printf("请输入第%d条边的两个端点下标:",k+1);
scanf("%c %c",&v1,&v2);
getchar();//输入一条边的两个顶点
i=locatevex(*g,v1);
j=locatevex(*g,v2);
if(i>=0&&j>=0){
//建立无向图的邻接表
/*s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=j;
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=i;
s->next=g->adjlist[j].firstedge;
g->adjlist[j].firstedge=s;*/
//建立有向图的邻接表
s=(ArcNode *)malloc(sizeof(ArcNode));
s->adjvex=j;
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;
}
}
}
int visited[maxsize];/* 访问标志数组*/
/*从第i个顶点出发递归地深度优先遍历图G*/
void DFS(graph g,int i)
{
ArcNode *p;
printf("%3c",g.adjlist[i].data);/*访问第i个项点*/
visited[i]=1;
p=g.adjlist[i].firstedge;
while(p!=NULL) {
if(visited[p->adjvex]==0)
DFS(g,p->adjvex);/*对i的尚未访问的邻接顶点j递归调用DFS*/
p=p->next;
}
}
void DFStraverse(graph g) /*对图G进行深度优先遍历*/
{
int v;
for (v=0; v<g.vex;v++)visited[v]=0; /*初始化标志数组*/
for (v=0; v<g.vex;v++) /*保证非连通图的遍历*/
/*从第v个顶点出发递归地深度优先遍历图G*/
if (!visited[v])DFS(g,v);
}
//循环队列存储结构定义
typedef struct cirqueue
{
ver *data; //队列存储空间的首地址
int front; //队头位置:指向当前队头元素
int rear; //队尾位置:指向当前队尾元素的下一位置
}cirqueue; // 循环队列
//构造空队,如果成功,返回1,如果失败,返回0
int initqueue(cirqueue *q)
{
q->data=(ver *)malloc(queuesize*sizeof(cirqueue));
if (q->data==NULL)return 0; // 存储分配失败
q->front=q->rear=0;
return 1;
}
// 插入元素e为Q的新的队尾元素 ,如果成功,返回1,如果失败,返回0
int enqueue (cirqueue *q,ver e)
{
if ((q->rear+1) % queuesize == q->front)
return 0; //队列满
q->data[q->rear] = e;
q->rear = (q->rear+1) % queuesize; //队尾后移一位
return 1;
}
//若队列不空,则删除Q的队头元素,用e返回其值,并返回1;否则返回0
int dequeue (cirqueue *q,int *e)
{
if (q->front == q->rear) return 0; //队列为空
*e = q->data[q->front];
q->front = (q->front+1) %queuesize; //队头后移一位
return 1;
}
//若栈不空,则用e返回队头元素,并返回1;否则返回0
int getfront(cirqueue q,ver *e)
{
if (q.front == q.rear) return 0; //队列为空
*e=q.data[q.front];
return 1;
}
//若队列为空栈,则返回1,否则返回0
int queueempty(cirqueue q)//栈非空
{
if(q.front == q.rear)return 1; //队列为空
else return 0;
}
//返回队列的元素个数,即队列的长度
int queuelength(cirqueue q)
{
return (q.rear-q.front+queuesize) % queuesize;
}
//【算法6-10:利用邻接矩阵实现连通图的广度优先搜索遍历】
int BFSvisited[maxsize];
cirqueue q;
/*从第k个顶点出发广度优先遍历图G,G以邻接矩阵表示。*/
void BFS(graph g,int k){
int i;
ArcNode *p;
initqueue(&q);/*初始化队列*/
printf("%3c",g.adjlist[k].data);/*访问第k个项点*/
visited[k]=1;
enqueue(&q,k);/*第k个顶点进队*/
while(queueempty(q)==0) {/*队列非空*/
dequeue(&q,&i);
p=g.adjlist[i].firstedge;/*获取第1个邻接点*/
while(p!=NULL){
if(visited[p->adjvex]==0){
/*访问第i个顶点的末曾访问的顶点*/
printf("%3c",g.adjlist[p->adjvex].data);
visited[p->adjvex]=1;
enqueue(&q,p->adjvex);/*第k个顶点进队*/
}
p=p->next;
}
}
}
void BFStraverse(graph g) //对图G进行广度优先遍历
{
int v;
for (v=0; v<g.vex;v++) //初始化标志数组
visited[v]=0;
for (v=0; v<g.vex;v++) //保证非连通图的遍历
if (!visited[v])BFS(g,v);
//从第v个顶点出发递归地深度优先遍历图G
}
int main()
{
graph g;
creategraph(&g);
print(g);
printf("\n");
printf("图的深度优先遍历序列:\n");
DFStraverse(g);
printf("\n");
printf("图的广度优先遍历序列:\n");
BFStraverse(g);
printf("\n");
return 0;
}