运用邻接表建立有向图,并进行深度优先遍历、广度广度优先遍历(c语言)
自认为深度和广度遍历的思路能够帮助大家更好地理解
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_VERTEX_NUM 20
int visited[MAX_VERTEX_NUM];
typedef int Status;
typedef char VertexType;
typedef int QElemType;
typedef struct ArcNode{
int adjvex;
struct ArcNode *nextarc; //链表的结点
}ArcNode;
typedef struct VNode{
VertexType data; //表的元素
ArcNode *firstarc; //指向下一个结点,即首个邻接点
}VNode,AdjList[MAX_VERTEX_NUM];
typedef struct{
AdjList vertices;
int vexnum,arcnum; //图的结点数和弧数
}ALGraph;
队列 (用于广度优先搜索)
//队列 (用于广度优先搜索)
typedef struct QNode{
QElemType date;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
Status InitQueue(LinkQueue *Q) //初始化队列
{
Q->front=Q->rear=(QueuePtr)malloc(sizeof(QNode));
if(!Q->front) return ERROR;
Q->front->next=NULL;
return OK;
}
//入队
Status EnQueue(LinkQueue *Q,QElemType e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if(!s) return ERROR;
s->date=e;
Q->rear->next=s;
s->next=NULL;
Q->rear=s;
return OK;
}
//出队
Status DeQueue(LinkQueue *Q,QElemType *e)
{
QueuePtr p;
if(Q->front==Q->rear) return ERROR;
p=Q->front->next;
*e=p->date;
Q->front->next=p->next;
if(p==Q->rear){
Q->rear=Q->front;
}
free(p);
return OK;
}
Status QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)
return OK;
else
return ERROR;
}//队列
//定位节点的位置
int LocateVexs(ALGraph A,VertexType ch)
{
int v;
for(v=0;v<A.vexnum;v++)
{
if(A.vertices[v].data==ch)
return v;
}
return -1;
}
//建立图
Status CreatALGraph(ALGraph *A)
{
int i;
int m,n;
VertexType a,b;
printf("请输入图的结点数和边的个数:");
scanf("%d%d",&(A->vexnum),&(A->arcnum));
printf("请输入结点元素:");
getchar();
for(i=0;i<A->vexnum;i++)
{
scanf("%c",&((A->vertices[i]).data));
A->vertices[i].firstarc=NULL;
}
printf("请输入边:\n点-点\n");
for(i=0;i<A->arcnum;i++)
{
ArcNode *s;
ArcNode *p;
s=(ArcNode*)malloc(sizeof(ArcNode));
if(!s) return ERROR;
getchar();
scanf("%c-%c",&a,&b);
m=LocateVexs(*A,a);
n=LocateVexs(*A,b);
s->adjvex=n;
s->nextarc=NULL;
if((A->vertices[m]).firstarc==NULL)
(A->vertices[m]).firstarc=s;
else{
p=(A->vertices[m]).firstarc;
while(p->nextarc)
{
p=p->nextarc;
}
p->nextarc=s;
}
}
return OK;
}
找出第一个邻接点
int FirstAdjVex(ALGraph A,int i)
{
if(i<0||i>=A.vexnum) return -1;
if(!A.vertices[i].firstarc) return -1; //当结点没有首节点是,应该返回-1; 【注】之前一直错这个
return A.vertices[i].firstarc->adjvex;
}
int NextAdjVex(ALGraph A,int i,int j)
{
ArcNode *p=A.vertices[i].firstarc;
if(!p) return -1;
if(i<0||i>=A.vexnum) return -1;
if(j<0||j>=A.vexnum) return -1;
while((p->adjvex!=j)&&(p->nextarc))
{
p=p->nextarc;
}
if(p&&(p->nextarc)) return (p->nextarc)->adjvex;
return -1;
}
深度遍历
//深度遍历
void DFS(ALGraph A,int v)
{
int w;
printf("%c",A.vertices[v].data); //输出第一个元素
visited[v]=1; //每输出一个元素则将visited[v] 赋值为1;
w=FirstAdjVex(A,v); //深度优先即为首先输出第一邻接点,同时临界
//链表的表示第一个邻接点的表示与后面的不同
while(w!=-1)
{
if(visited[w]==0)
DFS(A,w);
w=NextAdjVex(A,v,w); //当上面的递归结束后,进行到头结点后的结点
// printf("\nw=%d\n",w);
}
}
//深度排序,思路为:运用递归,将各个结点的第一个邻接顶点
void DFSTraverse(ALGraph A)
{
int v;
for(v=0;v<A.vexnum;v++)
visited[v]=0;
for(v=0;v<A.vexnum;v++) //用来控制所有点能够被访问,主要用来使非连通图
//的各个子图全部被访问
{
if(visited[v]==1)
continue;
DFS(A,v); //如果没有被访问,则将v作为输出的第一个元素;
}
}
广度遍历
void BFSTraverse(ALGraph A)
{
int w,v;
LinkQueue Q;
int e;
InitQueue(&Q);
for(v=0;v<A.vexnum;v++)
visited[v]=0;
for(v=0;v<A.vexnum;v++) //保证输出所有的结点,因为可能图部位可达图
{
if(visited[v]==1) continue;
printf("%c",A.vertices[v].data);
visited[v]=1;
EnQueue(&Q,v); //先将子图的首结点入队;
while(!QueueEmpty(Q)) //输出最大子图;
{
DeQueue(&Q,&e); //然后将队的头结点出队;
w=FirstAdjVex(A,e); //求出队的头结点的下一个
for(;w!=-1;w=NextAdjVex(A,e,w)) //循环将下一个元素全部输出完,并全部入队;
{
if(visited[w]==1) continue;
printf("%c",A.vertices[w].data);
visited[w]=1;
EnQueue(&Q,w);
}
}
}
}
主函数
int main()
{
ALGraph G;
CreatALGraph(&G);
printf("%d\n",FirstAdjVex(G,1));
printf("%d\n",NextAdjVex(G,1,2));
printf("深度优先:\n");
DFSTraverse(G);
printf("\n广度优先:\n");
BFSTraverse(G);
printf("\n");
return 0;
}