数据结构无向图的建立和遍历(邻接链表)
数据结构无向图的邻接链表的存储方式:顶点用一维数组储存,每个顶点构成一个线性表,用单链表的形式表达
1.结构体的创建
#define MAX 20 //线性表中的结点 typedef struct ENode{ int index; //该数据的下标 struct ENode *next;//下一个结构体 }ENode; //顶点信息 typedef struct Node{ char data; struct ENode *firstNode; //指向节点的指针 }Node; //链接表的信息 typedef struct Graph{ int vexNum; //顶点数量 int arcNum; //边的数量 Node vexs[MAX]; //顶点数组 用.的方式访问 }Graph,*myGraph;
2.无向图的邻接链表的创建
void createGraph(myGraph &G) { G=(Graph*)malloc(sizeof(Graph)); //结构体的指针要初始化 int i,j,k; char v1,v2; //边的两个顶点 printf("请输入顶点的数量:"); scanf("%d",&G->vexNum); printf("请输入边的数量:"); scanf("%d",&G->arcNum); printf("请依次将顶点数据输入进来\n"); for(i=0;i<G->vexNum;i++) { getchar(); scanf("%c",&G->vexs[i].data); G-> vexs[i].firstNode=NULL;//顶点指向的线性表为空 } printf("请依次将边输入进来\n"); for(int i=0;i<G->arcNum;i++) { getchar(); scanf("%c%c",&v1,&v2); j=getLocate(G,v1); //获取下标 k=getLocate(G,v2); //获取下标 //v1v2边 jk ENode *currentNode1=(ENode*)malloc(sizeof(Node));//生成临时结点 currentNode1->index=k; //储存的下标 currentNode1->next=NULL; //指针指向的节点为空 if(G->vexs[j].firstNode==NULL)//当该顶点没有邻接点时 { G->vexs[j].firstNode=currentNode1; //指向这个结点 } else //该顶点有邻接点时 { ENode *p=G->vexs[j].firstNode; //避免 G->vexs[j].firstNode 会发生改变 while(p->next!=NULL) //指向该顶点线性表中的最后一个节点 { p=p->next; } p->next=currentNode1; //指向这个结点 } //v2v1边 kj ENode *currentNode2=(ENode*)malloc(sizeof(Node));//生成临时结点 currentNode2->index=j; //储存的下标 currentNode2->next=NULL; //指针指向的节点为空 if(G->vexs[k].firstNode==NULL)//当该顶点没有邻接点时 { G->vexs[k].firstNode=currentNode2; //指向这个结点 } else //该顶点有邻接点时 { ENode *q=G->vexs[k].firstNode; //避免 G->vexs[j].firstNode 会发生改变 while(q->next!=NULL) //指向该顶点线性表中的最后一个节点 { q=q->next; } q->next=currentNode2; //指向这个结点 } } }
3.邻接链表的深度优先遍历
void DFS(myGraph G,int i,int *visit) { if(!visit[i])//如果没有访问过 { ENode *node;//临时结点 visit[i]=1; printf("%c ",G->vexs[i].data); //输出该顶点信息 node=G->vexs[i].firstNode; //避免破坏 G->vexs[i].firstNode while(node!=NULL)//该邻接点不为空 { if(!visit[node->index]) //如果该邻接点没有被访问过 { DFS(G,node->index,visit); } node=node->next; } } }
4.邻接链表的广度优先遍历
void BFS(myGraph G,int *visit) //队列满足先进先出的规律 { int front=0; int rear=0; int Queue[G->vexNum]; int i,j; ENode *node; for(i=0;i<G->vexNum;i++)//避免出现没有邻接点的顶点 { if(!visit[i]) //如果没有访问过 { visit[i]=1; //该顶点被访问过 printf("%c ",G->vexs[i].data); Queue[rear++]=i; //入队列 } while(front!=rear) { j=Queue[front++]; //出队列 node=G->vexs[j].firstNode; while(node!=NULL) { if(!visit[node->index]) { visit[node->index]=1; printf("%c ",G->vexs[node->index].data); Queue[rear++]=node->index; //入队列 } node=node->next; } } } }
所有的代码如下:
#include<stdio.h> #include<stdlib.h> #define MAX 20 //线性表中的结点 typedef struct ENode{ int index; //该数据的下标 struct ENode *next;//下一个结构体 }ENode; //顶点信息 typedef struct Node{ char data; struct ENode *firstNode; //指向节点的指针 }Node; //链接表的信息 typedef struct Graph{ int vexNum; //顶点数量 int arcNum; //边的数量 Node vexs[MAX]; //顶点数组 用.的方式访问 }Graph,*myGraph; //获取顶点的下标 int getLocate(myGraph G,char v) { int i; for(i=0;i<G->vexNum;i++) { if(v==G->vexs[i].data) { return i; } } return -1; } //创建链表 void createGraph(myGraph &G) { G=(Graph*)malloc(sizeof(Graph)); //结构体的指针要初始化 int i,j,k; char v1,v2; //边的两个顶点 printf("请输入顶点的数量:"); scanf("%d",&G->vexNum); printf("请输入边的数量:"); scanf("%d",&G->arcNum); printf("请依次将顶点数据输入进来\n"); for(i=0;i<G->vexNum;i++) { getchar(); scanf("%c",&G->vexs[i].data); G-> vexs[i].firstNode=NULL;//顶点指向的线性表为空 } printf("请依次将边输入进来\n"); for(int i=0;i<G->arcNum;i++) { getchar(); scanf("%c%c",&v1,&v2); j=getLocate(G,v1); //获取下标 k=getLocate(G,v2); //获取下标 //v1v2边 jk ENode *currentNode1=(ENode*)malloc(sizeof(Node));//生成临时结点 currentNode1->index=k; //储存的下标 currentNode1->next=NULL; //指针指向的节点为空 if(G->vexs[j].firstNode==NULL)//当该顶点没有邻接点时 { G->vexs[j].firstNode=currentNode1; //指向这个结点 } else //该顶点有邻接点时 { ENode *p=G->vexs[j].firstNode; //避免 G->vexs[j].firstNode 会发生改变 while(p->next!=NULL) //指向该顶点线性表中的最后一个节点 { p=p->next; } p->next=currentNode1; //指向这个结点 } //v2v1边 kj ENode *currentNode2=(ENode*)malloc(sizeof(Node));//生成临时结点 currentNode2->index=j; //储存的下标 currentNode2->next=NULL; //指针指向的节点为空 if(G->vexs[k].firstNode==NULL)//当该顶点没有邻接点时 { G->vexs[k].firstNode=currentNode2; //指向这个结点 } else //该顶点有邻接点时 { ENode *q=G->vexs[k].firstNode; //避免 G->vexs[j].firstNode 会发生改变 while(q->next!=NULL) //指向该顶点线性表中的最后一个节点 { q=q->next; } q->next=currentNode2; //指向这个结点 } } } //邻接链表的深度优先遍历 void DFS(myGraph G,int i,int *visit) { if(!visit[i])//如果没有访问过 { ENode *node;//临时结点 visit[i]=1; printf("%c ",G->vexs[i].data); //输出该顶点信息 node=G->vexs[i].firstNode; //避免破坏 G->vexs[i].firstNode while(node!=NULL)//该邻接点不为空 { if(!visit[node->index]) //如果该邻接点没有被访问过 { DFS(G,node->index,visit); } node=node->next; } } } //邻接链表的广度优先遍历 void BFS(myGraph G,int *visit) //队列满足先进先出的规律 { int front=0; int rear=0; int Queue[G->vexNum]; int i,j; ENode *node; for(i=0;i<G->vexNum;i++)//避免出现没有邻接点的顶点 { if(!visit[i]) //如果没有访问过 { visit[i]=1; //该顶点被访问过 printf("%c ",G->vexs[i].data); Queue[rear++]=i; //入队列 } while(front!=rear) { j=Queue[front++]; //出队列 node=G->vexs[j].firstNode; while(node!=NULL) { if(!visit[node->index]) { visit[node->index]=1; printf("%c ",G->vexs[node->index].data); Queue[rear++]=node->index; //入队列 } node=node->next; } } } } //打印该邻接表 void printfGraph(Graph G) //打印表不要用指针,这样可能会改变图的结构 { for(int i=0;i<G.vexNum;i++) { printf("%c ",G.vexs[i].data); while(G.vexs[i].firstNode!=NULL) { printf("%d ",G.vexs[i].firstNode->index); G.vexs[i].firstNode=G.vexs[i].firstNode->next; } printf("\n"); } } int main() { Graph *G; //申明邻接链表的对象 createGraph(G); //创建邻接链表 printfGraph(*G); //打印该邻接链表 int visit[G->vexNum]={0}; printf("图的邻接链表的深度优先遍历如下:\n"); for(int i=0;i<G->vexNum;i++) //避免出现没有邻接点的顶点 { DFS(G,i,visit); } printf("\n"); for(int i=0;i<G->vexNum;i++) { visit[i]=0; } printf("图的邻接链表的广度优先遍历如下:\n"); BFS(G,visit); return 0; }