/****************************************************************
C语言实现--邻接链表实现图的创建 遍历 DFS & BFS 递归及非递归方法
*****************************************************************/#defineINF65535#defineMAX_VERTEX_NUM20//最大顶点个数#include<stdio.h>#include<stdlib.h>#include<string.h>#include"SqStack.h"#include"SqQueue.h"typedefint VertexType;typedefint InfoType;typedefint AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];typedefenum{
DG,//有向图
DN,//有向网
UDG,//无向图
UDN//无向网} GraphKind;typedefstructArcNode{int adjvex;//该弧指向的顶点的位置structArcNode* nextarc;//指向下一条弧的指针
InfoType info;//该弧的相关信息}ArcNode;typedefstructVNode{
VertexType data;//顶点信息
ArcNode* firstarc;//指向第一条依附该顶点的弧的指针}VNode, AdjList[MAX_VERTEX_NUM];typedefstruct{
AdjList vertices;int vexnum, arcnum;//图的顶点数 和 弧数int kind;//图的种类}ALGraph;int vis[MAX_VERTEX_NUM];/*定位元素的位置*/intLocateVertex(ALGraph& G, VertexType v){for(int i =0; i < G.vexnum; i++){if(G.vertices[i].data == v)return i;}return-1;}/*创建有向图*/voidCreateDG(ALGraph &G){
ArcNode* p;for(int i =0; i < G.vexnum; i++){
G.vertices[i].data = i +1;
G.vertices[i].firstarc =NULL;}for(int k =0; k < G.arcnum; k++){
VertexType v1, v2;scanf("%d%d",&v1,&v2);int i =LocateVertex(G, v1);int j =LocateVertex(G, v2);/*j为入i为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j +1;
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;}}/*创建有向网*/voidCreateDN(ALGraph &G){
ArcNode* p;for(int i =0; i < G.vexnum; i++){
G.vertices[i].data = i +1;
G.vertices[i].firstarc =NULL;}for(int k =0; k < G.arcnum; k++){
VertexType v1, v2;int w;scanf("%d%d%d",&v1,&v2,&w);int i =LocateVertex(G, v1);int j =LocateVertex(G, v2);/*j为入i为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j +1;
p->info = w;
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;}}/*创建无向图*/voidCreateUDG(ALGraph &G){
ArcNode* p;for(int i =0; i < G.vexnum; i++){
G.vertices[i].data = i +1;
G.vertices[i].firstarc =NULL;}for(int k =0; k < G.arcnum; k++){
VertexType v1, v2;scanf("%d%d",&v1,&v2);int i =LocateVertex(G, v1);int j =LocateVertex(G, v2);/*j为入i为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j +1;
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;/*i为入j为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = i +1;
p->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p;}}/*创建无向网*/voidCreateUDN(ALGraph &G){
ArcNode* p;for(int i =0; i < G.vexnum; i++){
G.vertices[i].data = i +1;
G.vertices[i].firstarc =NULL;}for(int k =0; k < G.arcnum; k++){
VertexType v1, v2;int w;scanf("%d%d%d",&v1,&v2,&w);int i =LocateVertex(G, v1);int j =LocateVertex(G, v2);/*j为入i为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = j +1;
p->info = w;
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;/*i为入j为出创建邻接链表*///p = new ArcNode;
p =(ArcNode*)malloc(sizeof(ArcNode));
p->adjvex = i +1;
p->info = w;
p->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p;}}/*打印图的邻接链表*/voidDisplayALGraph(ALGraph &G){
ArcNode* p;for(int i =0; i < G.vexnum; i++){printf("%d-->", G.vertices[i].data);
p = G.vertices[i].firstarc;if(p ==NULL)printf("NULL");while(p){if(G.kind ==1|| G.kind ==3)printf("%d ", p->adjvex);elseif(G.kind ==2|| G.kind ==4)printf("%d,%d ", p->adjvex, p->info);
p = p->nextarc;}printf("\n");}}/*
递归深度优先遍历
函数功能:DFS递归遍历图(邻接表)
函数说明:建立一个标记数组vis[], 若该顶点访问过就标记为1,否则置零;
递归的时候,从某个指定定点开始进行,遍历第一个邻接点,然后再遍历
邻接点的第一个邻接点......直到某个顶点没有未访问的邻接点,就退
出该层递归,然后再进入上一层递归,直到所有的顶点都没有未访问的顶点
dfs遍历结束。每一次大的for循环结束就找到了一个连通子集。
*/voidDFSRecursiveTraverse(ALGraph& G,int i){printf("%d ",G.vertices[i].data);//输出顶点值
ArcNode* p = G.vertices[i].firstarc;//指向第一个邻接顶点
vis[i]=1;//v已经访问过了while(p){
VertexType u = p->adjvex -1;//顶点序号if(!vis[u])//没访问过{DFSRecursiveTraverse(G, u);//从该节点的邻接点出发继续深度优先遍历}
p = p->nextarc;//从某顶点出发深度优先遍历结束了 回溯到上一个顶点p 指向上一个节点的其他邻接点}}/*
非递归DFS遍历图
压栈的顺序就是深度优先遍历的顺序
3
8
9
1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 8
6 7
*/voidDFSNonrecursiveTraverse(ALGraph &G,int i){
vis[i]=1;//该顶点已经访问
SqStack S;InitStack(S);Push(S, G.vertices[i].data);//将顶点压栈//printf("%d ",G.vertices[i].data);printf("%d 入栈\n", G.vertices[i].data);while(!IsEmptyS(S)){//栈不空
VertexType e;GetTop(S, e);//得到栈顶元素int k =LocateVertex(G, e);
ArcNode *p = G.vertices[k].firstarc;//指向第一个邻接点while(p)//只要有邻接点{int j =LocateVertex(G, p->adjvex);//定位顶点索引if(!vis[j])//该顶点没有被访问{//置访问标志
vis[j]=1;//压栈Push(S, G.vertices[j].data);printf("%d 入栈\n", G.vertices[j].data);//printf("%d ",G.vertices[j].data);
p = G.vertices[j].firstarc;//指向下一顶点的第一个邻接点}else//该顶点已经被访问了{//继续访问下一个邻接点
p = p->nextarc;//当某个顶点的所有邻接点都访问完之后 p就会变成NULL}}//此时退出循环if(p ==NULL){
VertexType v;Pop(S, v);//将所有邻接点都访问完的顶点出栈printf("%d 出栈\n", v);}}ClearStack(S);}/*递归DFS遍历图*/voidDFSTraverse(ALGraph &G,int type){memset(vis,0,sizeof(vis));//初始化为0for(int i =0; i < G.vexnum; i++){if(!vis[i]&& type ==0)//递归{//遍历每个顶点DFSRecursiveTraverse(G, i);}if(!vis[i]&& type ==1)//非递归{//遍历每个顶点DFSNonrecursiveTraverse(G, i);}}}/**************************************************************
函数功能:BFS非递归遍历图(邻接表)
函数说明:建立一个标记数组vis[],若该顶点访问过就标记为1,否则置零;
遍历的时候,首先找到一个未访问的顶点,入队,然后如果队列不空,就
一直循环,并且每次循环都要出队一个元素,再在以该元素为顶点的链表
或者矩阵的某一行中进行查找,如果某个顶点未访问,则进行访问,然后
vis置1,表示已经访问,再入队,直到队为空,退出本次循环,再查找顶
点表中的第二个顶点或者矩阵中的第二行,以此类推得到广度优先搜索序
列,每次大的循环其实就是一个连通子集。
***************************************************************/voidBFS(ALGraph &G,int i){
vis[i]=1;
SqQueue Q;InitQueue(Q);EnQueue(Q, G.vertices[i].data);//入队printf("%d 入队\n", G.vertices[i].data);while(!IsEmptyQ(Q)){
VertexType e;DeQueue(Q, e);printf("%d 出队\n", e);int k =LocateVertex(G, e);
ArcNode *p = G.vertices[k].firstarc;while(p){int j =LocateVertex(G, p->adjvex);if(!vis[j]){
vis[j]=1;//访问过了//入队EnQueue(Q, G.vertices[j].data);printf("%d 入队\n",G.vertices[j].data);}
p = p->nextarc;}}ClearQueue(Q);}/*入队序列就是BFS遍历结果*/voidBFSTraverse(ALGraph &G){memset(vis,0,sizeof(vis));//初始化为0for(int i =0; i < G.vexnum; i++){if(!vis[i]){BFS(G, i);}}}/*根据图的种类创建图*/voidCreateGraph(ALGraph &G){printf("请输入图的种类(1-有向图, 2-有向网, 3-无向图, 4-无向网):");scanf("%d",&G.kind);printf("请输入创建图的顶点数:");scanf("%d",&G.vexnum);printf("请输入创建的图的边/弧数:");scanf("%d",&G.arcnum);printf("请输入弧依附的顶点信息:\n");switch(G.kind){case1://DGCreateDG(G);break;case2://DNCreateDN(G);break;case3://UDGCreateUDG(G);break;case4://UDNCreateUDN(G);break;}}intmain(){
ALGraph G;CreateGraph(G);DisplayALGraph(G);printf("DFS递归遍历结果:");DFSTraverse(G,0);printf("\n");printf("DFS非递归遍历结果:\n");DFSTraverse(G,1);printf("\n");printf("BFS非递归遍历结果:\n");BFSTraverse(G);printf("\n");return0;}
SqQueue.h
#defineTRUE1#defineFALSE0#defineOK1#defineERROR0#defineQUEUE_INIT_SIZE100#defineOVERFLOW-2typedefint Status;typedefint QElemType;typedefstruct{
QElemType* base;int front;int rear;} SqQueue;//顺序表实现队列 非循环队列
Status InitQueue(SqQueue& Q);
Status EnQueue(SqQueue& Q, QElemType e);
Status DeQueue(SqQueue& Q, QElemType& e);
Status IsEmptyQ(SqQueue& Q);
Status GetFront(SqQueue& Q, QElemType& e);voidClearQueue(SqQueue &Q);
SqQueue.cpp
#include<stdio.h>#include<stdlib.h>#include"SqQueue.h"
Status InitQueue(SqQueue& Q){
Q.base =(QElemType*)malloc(sizeof(QElemType)* QUEUE_INIT_SIZE);if(!Q.base)exit(OVERFLOW);
Q.front = Q.rear =0;return OK;}
Status EnQueue(SqQueue& Q, QElemType e){
Q.base[Q.rear]= e;
Q.rear = Q.rear +1;//循环队列//Q.rear = (Q.rear + 1)%(QUEUE_INIT_SIZE + 1);return OK;}
Status DeQueue(SqQueue& Q, QElemType& e){if(Q.front == Q.rear){return ERROR;}
e = Q.base[Q.front];//循环队列//Q.front = (Q.front + 1) % (QUEUE_INIT_SIZE + 1);
Q.front = Q.front +1;return OK;}
Status IsEmptyQ(SqQueue& Q){if(Q.front == Q.rear)return TRUE;return FALSE;}
Status GetFront(SqQueue& Q, QElemType& e){if(Q.front == Q.rear)return ERROR;
e = Q.base[Q.front];return OK;}voidClearQueue(SqQueue &Q){free(Q.base);
Q.base =NULL;
Q.front = Q.rear;}
SqStack.h
#defineERROR0#defineOK1#defineTRUE1#defineFALSE0#defineSTACK_INIT_SIZE100#defineSTACK_INCREMENT10#defineOVERFLOW-2typedefint SElemType;typedefint Status;typedefstruct{
SElemType* base;
SElemType* top;int stacksize;} SqStack;
Status InitStack(SqStack& S);
Status GetTop(SqStack& S, SElemType& e);
Status Push(SqStack& S, SElemType e);
Status Pop(SqStack& S, SElemType& e);
Status IsEmptyS(SqStack& S);voidClearStack(SqStack& S);