课程名称:数据结构与算法
课程类型:必修
实验项目:图型结构的建立与搜索
实验题目:图的存储结构的建立与搜索
实验日期:2017/12/3
一、实验目的
图的搜索(遍历)算法是图型结构相关算法的基础,本实验要求编写程序演示无向图三种典型存储结构的建立和搜索(遍历)过程。让我们在这个过程中熟悉这些操作之间的关系和内在联系。
二、实验要求及实验环境
1.分别实现无向图的邻接矩阵、邻接表和邻接多重表存储结构的建立算法,分析和比较各建立算法的时间复杂度以及存储结构的空间占用情况;
2.实现无向图的邻接矩阵、邻接表和邻接多重表三种存储结构的相互转换的算法;
3.在上述三种存储结构上,分别实现无向图的深度优先搜索(递归和非递归)和广度优先搜索算法。并以适当的方式存储和显示相应的搜索结果(深度优先或广度优先生成森林(或生成树)、深度优先或广度优先序列和编号);
4.分析搜索算法的时间复杂度;
5.以文件形式输入图的顶点和边,并显示相应的结果。要求顶点不少于 10 个,边不少于 13 个;
6.软件功能结构安排合理,界面友好,便于使用。
实验环境:
Win10/code blocks
三、设计思想
(本程序中的用到的所有数据类型的定义,主程序的流程图及各程序模块之间的调用关系)
1.逻辑设计
define NumVertices 25//顶点数目最大值
//using namespace std;
/*
无向图的邻接矩阵
*/
typedef char VertexData[5];//保存顶点名称数组
typedef int EdgeData;//保存该点的值
typedef struct
{
VertexData vertex[NumVertices];//顶点表,里面是所有顶点名称
EdgeData edge[NumVertices][NumVertices]; //邻接矩阵—边表, 可视为顶点之间的关系
int n, e; //图的顶点数与边数
} MTGraphSquare;
/*
无向图的邻接表
*/
typedef struct node //边表结点
{
int adjvex; //邻接点域(下标)
EdgeData cost; //边上的权值
struct node *next; //下一边链接指针
} EdgeNode;
typedef struct //顶点表结点
{
VertexData vertex; //顶点数据域
EdgeNode *firstedge;//边链表头指针
} VertexNode;
typedef struct //图的邻接表
{
VertexNode vexlist[NumVertices];// 顶点表,里面是所有顶点名称
int n, e; //顶点个数与边数
} AdjGraph;
typedef bool VisitIf;//是否访问过
typedef struct InfoType//信息域
{
VertexData vertex1;
VertexData vertex;
int weight;
} InfoType;
typedef struct EBox//节点box
{
VisitIf mark; //边访问标记
int ivex, jvex; //该边依附的两个顶点的位置
struct EBox * ilink, * jlink; //分别指向依附这两个顶点的下一条边
InfoType info; //该边信息指针
} EBox;
typedef struct VexBox//顶点box
{
VertexData data;
EBox * firstedge; //指向第一条依附于该顶点的边
} VexBox;
typedef struct
{
VexBox adjmulist[MAX_VERTEX_NUM];
int vexnum,edgenum; //无向图的当前顶点数和边数
} AMLGraph;
bool visited[50]= {false}; //是否进行过访问
下面是相应的图示。
2.物理设计
int AMLGraphDFSTraverseFeidiguiBUG2(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
int AMLGraphDFSTraverseFeidiguiBUG3(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
Status AMLGraphDFSTraverseFeidigui(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
void AMLGraphBFSTraverse(AMLGraph *G)
int NextAdjVex(AMLGraph *G,VertexData v,VertexData w)//返回v的(相对于w的)下一个邻接顶点
int FirstAdjVex(AMLGraph *G,VertexData v)//寻找v的第一个邻接顶点
void AMLGraphDFSTraverse(AMLGraph *G)
void AMLGraphDFS(AMLGraph *G,int v)
//深度优先(非递归)
//LGraph: 邻接表
//InitVertex: 遍历起始顶点
void AdjGraphDFS2(AdjGraph *LGraph, int InitVertex)
void AdjGraphBFS(AdjGraph *G,int s)
//广度优先遍历 (递归)
//缺点递归最大为G.numv次
//深度优先遍历主程序
void AdjGraphDFSTraverse(AdjGraph *G)
void AdjGraphDFS1(AdjGraph *G,int i)
void MTGraphSquareDFSTraverse2(MTGraphSquare *G)
void MTGraphSquareDFS2(MTGraphSquare *G, int i)
void MTGraphSquareBFSTraverse(MTGraphSquare *G, char vName[5])
int MTGraphSquareLocateVex(MTGraphSquare *G, char name[5])
//v相对于w的下一个邻接点
int MTGraphSquareNextAdjVex(MTGraphSquare *G, int v, int w)
//广度优先遍历
//v的第一个邻接点
int MTGraphSquareFirstAdjVex(MTGraphSquare *G, int v)
void MTGraphSquareDFSTravel(MTGraphSquare *G)
void MTGraphSquareDFS(MTGraphSquare *G, int i)//以vi为出发点对邻接矩阵表示的图G进行深度优先搜索
//总而言之,就是对于表的遍历和建立两个联合起来。
AdjGraph TransAMLraphSquareToAdjGraph(AMLGraph *T)
MTGraphSquare TransAMLGraphSquareToMTGraph(AMLGraph *G)
AMLGraph TransMTGraphSquareToAMLGraph(MTGraphSquare *T)
AMLGraph TransAdjGraphSquareToAMLGraph(AdjGraph *T)
MTGraphSquare TransAdjGraphSquareToMTGraph(AdjGraph *G)
AdjGraph TransMTGraphSquareToAdjGraph(MTGraphSquare *T)//邻接矩阵初始化
void PrintInitUDGAMLFalse(AMLGraph *G)//无法逆向访问
void PrintInitUDGAMLTrue(AMLGraph *G)
void InitUDGAML(AMLGraph *G) //用邻接多重表存储,构造无向图G
void DisplayAML(AMLGraph *G)
void MarkUnvizitedAML(AMLGraph *G)
/* bo7-4.c 无向图的邻接多重表存储(存储结构由c7-4.h定义)的基本函数类型(16个) */
int LocateVex(AMLGraph *G,VertexData u)
void PrintAdjGraph (AdjGraph *G)
void CreateAdjGraph (AdjGraph *G)//邻接表初始化
void PrintMTGraphSquare(MTGraphSquare *T)//邻接矩阵打印
void InitMTGraphSquare(MTGraphSquare *T)//邻接矩阵初始
从main函数开始启动程序,根据输入的choice来判断要进入哪一个函数。根据界面的提示:
printf("Please input your choice.INPUT 18 to exit\n");
printf("0:初始化邻接矩阵(MTGraph)\n");
printf("1:深度优先递归邻接矩阵(MTGraph)\n");
printf("2:广度优先递归邻接矩阵(MTGraph)\n");
printf("3:深度优先非递归邻接矩阵(MTGraph)\n");
printf("4:邻接矩阵到邻接多重表的转换(MTGraph)\n");
printf("5:邻接矩阵到邻接表的转换(MTGraph)\n");
printf("6:初始化邻接表(AdjGraph)\n");
printf("7:深度优先递归邻接表(AdjGraph)\n");
printf("8:广度优先递归邻接表(AdjGraph)\n");
printf("9:深度优先非递归邻接表(AdjGraph)\n");
printf("10:邻接表到邻接矩阵的转换(AdjGraph)\n");
printf("11:邻接表到邻接多重表的转换(AdjGraph)\n");
printf("12:初始化邻接多重表(AMLGraph)\n");
printf("13:深度优先递归邻接多重表(AMLGraph)\n");
printf("14:广度优先递归邻接多重表(AMLGraph)\n");
printf("15:深度优先非递归邻接多重表(AMLGraph)\n");
printf("16:邻接多重表到邻接矩阵的转换(AMLGraph)\n");
printf("17:邻接多重表到邻接表的转换(AMLGraph)\n");
printf("INPUT 18 to exit\n");
scanf("%d",&choice);
getchar();
这些函数互相直接几乎没有调用关系,但是每次开始都会清除一次bool visited[]数组,使得全为false。便于访问表的时候记录是否访问过该位置。
其实这些存储结构之间的转换都是很相似的,访问方式和顺序也是相似的,但是具体的存储结构的不同,要具体去写还是会在实际中遇到很多问题。六个表之间的转换其实步骤都是相似的,只是把数据都给读出来,然后按照相应的表储存。
示例数据保存的图如下面的图表示。
dfs搜索的时间复杂度分析:
邻接表:O(n+e) ;邻接矩阵:O(n2);多重邻接表O(n+e)
dfs遍历的大致流程如下图:
void DFS1 (AdjGraph* G, int i)
//以vi为出发点时对邻接表表示的图G进行先深搜索
{ EdgeNode *p;
cout<<G→vexlist[i].vertex;
visited[i]=TRUE;
dfn[i]=count++;
p=G→vexlist[i].firstedge;
while( p ) {
if( !visited[ p→adjvex ] )
DFS1(G, p→adjvex);
p=p→next;
}
}
bfs搜索的时间复杂度分析:
邻接表:O(n+e) ;邻接矩阵:O(n2);多重邻接表O(n+e)
bfs遍历的大致流程如下图:
bool visited[NumVertices]; //访问标记数组是全局变量
int dfn[NumVertices]; //顶点的先深编号
void BFSTraverse (AdjGraph G) //主算法
/* 先广搜索一邻接表表示的图G;而以邻接矩阵表示G时,算法
完全相同 */
{ int count = 1;
for ( int i = 0; i < G.n; i++ )
visited [i] =FALSE; //标志数组初始化
for ( int i = 0; i < G.n; i++ )
if ( ! visited[i] )
BFSX ( G, i ); //从顶点 i 出发的一次搜索,DFSX (G, i )
}
邻接矩阵的三个遍历函数:
void MTGraphSquareDFS(MTGraphSquare *G, int i)//以vi为出发点对邻接矩阵表示的图G进行深度优先搜索
{
int j;
cout<<G->vertex[i]<<" "; //访问定点vi
visited[i]=true; //标记vi已访问
for( j=0; j<G->n; j++ ) //依次搜索vi的邻接点
{
//cout<<"\t"<<j;
if ( (G->edge[i][j] >= 1)&&!visited[j] ) //若vj尚未访问
{
MTGraphSquareDFS(G,j);
}
}
}
void MTGraphSquareDFSTravel(MTGraphSquare *G)
{
int i;
for(i=0; i<G->n; i++)
visited[i]=false;
for(i=0; i<G->n; i++)
{
if(visited[i]==false)
{
MTGraphSquareDFS(G,i);
}
}
printf("\n");
}
/************************************************************************/
/* 广度优先遍历(广度优先搜索) */
/************************************************************************/
//广度优先遍历
//v的第一个邻接点
int MTGraphSquareFirstAdjVex(MTGraphSquare *G, int v)
{
for (int i = 0; i < G->n; i++)
{
if (G->edge[v][i] != 0)
{
return i;
}
}
return -1;
}
//v相对于w的下一个邻接点
int MTGraphSquareNextAdjVex(MTGraphSquare *G, int v, int w)
{
for (int i = w + 1; i < G->n; i++)
{
if (G->edge[v][i] != 0)
{
return i;
}
}
return -1;
}
int MTGraphSquareLocateVex(MTGraphSquare *G, char name[5])
{
for (int i = 0; i < G->n; i++)
{
if (0 == strcmp(G->vertex[i], name))
{
return i;
}
}
return -1;
}
void MTGraphSquareBFSTraverse(MTGraphSquare *G, char vName[5])
{
int pos = MTGraphSquareLocateVex(G, vName);
for (int v = 0; v < G->n; v++)
{
visited[v] = false;
}
queue<int> q;
if (!visited[pos])
{
cout<<G->vertex[pos]<<'\t';
visited[pos] = true;
}
q.push(pos);
while (!q.empty())
{
int v = q.front();
q.pop();
for (int w = MTGraphSquareFirstAdjVex(G, v); w >= 0; w = MTGraphSquareNextAdjVex(G, v, w))
{
if (!visited[w])
{
cout<<G->vertex[w]<<'\t';
visited[w] = true;
q.push(w);
}
}
}
cout<<endl;
}
void MTGraphSquareDFS2(MTGraphSquare *G, int i)
{
int j;
stack<int> S;
S.push(i);
printf("%s",G->vertex[i]);
printf("\t");
visited[0] = 1;
while(!S.empty())
{
S.pop();
for(j = 0; j < G->n; j ++)
{
if(G->edge[i][j] && !visited[j])
{
S.push(j);
printf("%s",G->vertex[j]);
printf("\t");
visited[j] = 1;
i = j;
j = 0;
}
}
if(!S.empty())
{
S.pop();
}
}
}
void MTGraphSquareDFSTraverse2(MTGraphSquare *G)
{
int i;
for(i = 0; i < G->n; i ++)
visited[i] = 0;
for(i = 0; i < G->n; i ++)
{
if(!visited[i])
MTGraphSquareDFS2(G,i);
}
printf("\n");
}
void AdjGraphDFS1(AdjGraph *G,int i)
{
EdgeNode *p;
cout<<G->vexlist[i].vertex<<endl;
visited[i] = true;
p = G->vexlist[i].firstedge;
while(p)
{
if(!visited[p->adjvex])
AdjGraphDFS1(G,p->adjvex);
p = p->next;
}
}
//深度优先遍历主程序
void AdjGraphDFSTraverse(AdjGraph *G)
{
int i ;
for(i=0; i<G->n; i++)
visited[i]=false;
for(i=0; i<G->n; i++)
if(!visited[i])
AdjGraphDFS1(G,i);
}
邻接表的三个遍历函数:
//广度优先遍历 (递归)
//缺点递归最大为G.numv次
int r=0;
int f=0;
int q[100];
void AdjGraphBFS(AdjGraph *G,int s)
{
if(!visited[s])
{
printf("%s",G->vexlist[s].vertex);
cout<<" ";
visited[s] = 1;
EdgeNode* p = G->vexlist[s].firstedge;
while(p != NULL)
{
if(!visited[p->adjvex])
q[r++] = p->adjvex;
p = p->next;
}
}
while(f < r)
{
AdjGraphBFS(G,q[f++]);
}
}
//深度优先(非递归)
//LGraph: 邻接表
//InitVertex: 遍历起始顶点
void AdjGraphDFS2(AdjGraph *LGraph, int InitVertex)
{
int stack[25]; //栈
int top = -1;
EdgeNode* pEdge = NULL;
int Pre[25];
int index = -1; //Pre数组的下标
visited[InitVertex] = true; //起始顶点标记已访问
cout << InitVertex << " "; //输出起始顶点
//把所有与起始顶点关联的顶点存入Per数组中
pEdge = LGraph->vexlist[InitVertex].firstedge;
while (NULL != pEdge)
{
Pre[++index] = pEdge->adjvex;
pEdge = pEdge->next;
}
//逆序把Pre数组中的顶点加入栈中
for (int i = index; i >= 0; i--)
{
top++;
stack[top] = Pre[i];
visited[Pre[i]] = 1; //入栈的顶点标记已访问
}
while (top > -1)
{
int TopVertex = stack[top];
top--;
cout << TopVertex << " "; //输出栈顶节点
pEdge = LGraph->vexlist[TopVertex].firstedge; //把所有与栈底顶点关联且未访问过的顶点入栈
index = -1; //重置Pre数组下标
while (NULL != pEdge)
{
if (visited[pEdge->adjvex] == 0)
Pre[++index] = pEdge->adjvex;
pEdge = pEdge->next;
}
for (int i = index; i >= 0; i--) //逆序把Pre数组中的顶点加入到栈中
{
top++;
stack[top] = Pre[i];
visited[Pre[i]] = 1;
}
}//end while(top > -1)
}
/*void AdjGraphDFS(AdjGraph *T, int v)
{
visited[v] = true;
cout << T.vexlist[v].vertex << " ";
EBox* p= T.vexlist[v].firstedge;
while (p)
{
if (!visited[p->adjvex])
DFSAdjGraph(T, p->adjvex);
p = p->next;
}
}
void AdjGraphDFSTraverse(AdjGraph *T)
{
for (int i = 0; i < T.vexNum; i++)//初始化访问标志数组
visited[i] = false;
for (int i = 0; i < T.vexNum; i++)
{
if (!visited[i])//如果没有访问
DFSAdjGraph(T, i);
}
*/
void AMLGraphDFS(AMLGraph *G,int v)
{
int j;
EBox *p;
printf("%s\t",G->adjmulist[v].data);
visited[v]=true;
p=G->adjmulist[v].firstedge;
while(p)
{
j=p->ivex==v?p->jvex:p->ivex;
if(!visited[j])
AMLGraphDFS(G,j);
p=p->ivex==v?p->ilink:p->jlink;
}
}
void AMLGraphDFSTraverse(AMLGraph *G)
{
/* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.4 */
/* 操作结果: 从第1个顶点起,深度优先遍历图G,并对每个顶点调用函数Visit */
/* 一次且仅一次。一旦Visit()失败,则操作失败 */
int v;
for(v=0; v<G->vexnum; v++)
if(!visited[v])
AMLGraphDFS(G,v);
printf("\n");
}
int FirstAdjVex(AMLGraph *G,VertexData v)//寻找v的第一个邻接顶点
{
int i;
i=LocateVex(G,v);
if(i<0)
return -1;
if(G->adjmulist[i].firstedge)//v有邻接顶点
if(G->adjmulist[i].firstedge->ivex==i)
return G->adjmulist[i].firstedge->jvex;
else
return G->adjmulist[i].firstedge->ivex;
else
return -1;
}
int NextAdjVex(AMLGraph *G,VertexData v,VertexData w)//返回v的(相对于w的)下一个邻接顶点
{
int i,j;
EBox *p;
i=LocateVex(G,v);//i是顶点v的序号
j=LocateVex(G,w); //j是顶点w的序号
if(i<0||j<0)//v或w不是G的顶点
return -1;
p=G->adjmulist[i].firstedge; //p指向顶点v的第1条边
while(p)
if(p->ivex==i && p->jvex!=j) //不是邻接顶点w(情况1)
p=p->ilink; //找下一个邻接顶点
else if(p->jvex==i && p->ivex!=j) //不是邻接顶点w(情况2)
p=p->jlink; //找下一个邻接顶点
else //是邻接顶点w
break;
if(p&&p->ivex==i&&p->jvex==j) //找到邻接顶点w(情况1)
{
p=p->ilink;
if(p&&p->ivex==i)
return p->jvex;
else if(p&&p->jvex==i)
return p->ivex;
}
if(p&&p->ivex==j&&p->jvex==i)//找到邻接顶点w(情况2)
{
p=p->jlink;
if(p&&p->ivex==i)
return p->jvex;
else if(p&&p->jvex==i)
return p->ivex;
}
return -1;
}
邻接多重表的三个遍历函数:
void AMLGraphBFSTraverse(AMLGraph *G)
{
/* 初始条件: 图G存在,Visit是顶点的应用函数。算法7.6 */
/* 操作结果: 从第1个顶点起,按广度优先非递归遍历图G,并对每个顶点调用函数 */
/* Visit一次且仅一次。一旦Visit()失败,则操作失败。 */
/* 使用辅助队列Q和访问标志数组visite */
int v=0,u=0,w=0;
VertexData w1,u1;
queue<int> Q;
for(v=0; v<G->vexnum; v++)
if(!visited[v]) /* v尚未访问 */
{
visited[v]=true; /* 设置访问标志为TRUE(已访问) */
printf("%s\t",G->adjmulist[v].data);
Q.push(v);/* v入队列 */
while(!Q.empty()) /* 队列不空 */
{
Q.pop(); /* 队头元素出队并置为u */
strcpy(u1,G->adjmulist[u].data);
for(w=FirstAdjVex(G,u1); w>=0; w=NextAdjVex(G,u1,strcpy(w1,G->adjmulist[w].data)))
if(!visited[w]) /* w为u的尚未访问的邻接顶点的序号 */
{
visited[w]=true;
printf("%s\t",G->adjmulist[w].data);
Q.push(w);
}
}
}
printf("\n");
}
//still someBUG
void AMLGraphDFSTraverseFeidiguiBUG(AMLGraph *LGraph, int InitVertex)
{
int stack[25]; //栈
int top = -1;
EBox * pEdge = NULL;
int Pre[25];
int index = -1; //Pre数组的下标
visited[InitVertex] = true; //起始顶点标记已访问
cout << InitVertex << " "; //输出起始顶点
//把所有与起始顶点关联的顶点存入Per数组中
pEdge = LGraph->adjmulist[InitVertex].firstedge;
while (NULL != pEdge)
{
Pre[++index] = pEdge->ivex;
pEdge = pEdge->ilink;
}
//逆序把Pre数组中的顶点加入栈中
for (int i = index; i >= 0; i--)
{
top++;
stack[top] = Pre[i];
visited[Pre[i]] = 1; //入栈的顶点标记已访问
}
while (top > -1)
{
int TopVertex = stack[top];
top--;
cout << TopVertex << " "; //输出栈顶节点
pEdge = LGraph->adjmulist[TopVertex].firstedge; //把所有与栈底顶点关联且未访问过的顶点入栈
index = -1; //重置Pre数组下标
while (NULL != pEdge)
{
if (visited[pEdge->ivex] == 0)
Pre[++index] = pEdge->ivex;
pEdge = pEdge->ilink;
}
for (int i = index; i >= 0; i--) //逆序把Pre数组中的顶点加入到栈中
{
top++;
stack[top] = Pre[i];
visited[Pre[i]] = 1;
}
}//end while(top > -1)
}
typedef int Status;
#define OK 1
#define TRUE 1
#define ERROR 0
#define FALSE
typedef int SElemType;
typedef int QElemType;
typedef struct//栈结构
{
SElemType *base;
SElemType *top;
int stacksize;
}SqStack;
Status InitStack(SqStack &S)
{
S.base=(SElemType *)malloc(100*sizeof(SElemType));
if(!S.base)
exit(0);
S.top=S.base;
S.stacksize=100;
return OK;
}
Status DestroyStack(SqStack &S)
{
free(S.base);
S.base=NULL;
S.top=NULL;
S.stacksize=0;
return OK;
}
Status Push(SqStack &S,SElemType e)
{
if(S.top-S.base>=S.stacksize)
{
S.base=(SElemType*)realloc(S.base,(S.stacksize+100)*sizeof(SElemType));
if(!S.base)
exit(0);
S.top=S.base+S.stacksize;
S.stacksize+=100;
}
*S.top++=e;
return OK;
}
Status Pop(SqStack &S,SElemType &e)
{
if(S.top==S.base)
return ERROR;
e=*--S.top;
return OK;
}
Status StackEmpty(SqStack S)
{
if(S.top==S.base)
return OK;
else
return ERROR;
}
Status AMLGraphDFSTraverseFeidigui(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
{
int v,w,u;
SqStack S,S2;
InitStack(S);
InitStack(S2);
w=LocateVex(G,start);
for(v=0;v<G->vexnum;v++)
visited[v]=0;
for(v=0;v<G->vexnum;v++)
if(!visited[(v+w)%G->vexnum])
{
Push(S,(v+w)%G->vexnum);
while(!StackEmpty(S))
{
Pop(S,u);
if(!visited[u])
{
visited[u]=1;
printf("%s\t",G->adjmulist[u].data);
for(w=FirstAdjVex(G,G->adjmulist[u].data);w>=0;
w=NextAdjVex(G,G->adjmulist[u].data,G->adjmulist[w].data))
if(!visited[w])
Push(S2,w);
while(!StackEmpty(S2))
{
Pop(S2,u);
Push(S,u);
}
}
}
}
return OK;
}
int AMLGraphDFSTraverseFeidiguiBUG3(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
{
/*test
*/
int v=0,w=0,u=0;
stack<int> S,S2;
w=LocateVex(G,start);
printf("-----%d-----\n",w);
for(v=0; v<G->vexnum; v++)
if(!visited[(v+w)%G->vexnum])
{
printf("??%d??\t",(v+w)%G->vexnum);
printf("-----looping-----\n");
S.push((v+w)%G->vexnum);
while(!S.empty())
{
printf("u:%d \n",u);
S.pop();
if(!visited[u])
{
printf("#####looping####\n");
visited[u]=true;
printf("%s",G->adjmulist[u].data);
for(w=FirstAdjVex(G,G->adjmulist[u].data); w>=0;
w=NextAdjVex(G,G->adjmulist[u].data,G->adjmulist[w].data))
if(!visited[w])
{
S2.push(w);
printf("Panduan\n");
}
while(!S2.empty())
{
printf("#####S2####\n");
S2.pop();
S.push(u);
}
}
}
}
return 1;
}
int AMLGraphDFSTraverseFeidiguiBUG2(AMLGraph *G,VertexData start)//从start顶点起,深度优先遍历图G(非递归算法)
{
int v=0,w=0;
stack<int> S;
w=LocateVex(G,start);
printf("-----%d-----\n",w);
EBox *p;
for(v=0; v<G->vexnum; v++)
{
p=G->adjmulist[w].firstedge;
S.push(w);
visited[w]=true;
if(!visited[w])
printf("%s",G->adjmulist[w].data);
for(int i=0;visited[p->ivex]!=false;i++)
{
}
while(p!=NULL)
{
w=p->ivex;
}
}
return 1;
}
访问每个图的函数分别为:
1:邻接矩阵:
void PrintMTGraphSquare(MTGraphSquare *T)//邻接矩阵打印
{
int i,j;
printf("邻接矩阵打印(PrintMTGraphSquare)\n \t");
for(i=0; i<T->n; i++)
printf("%d ",i);
printf("\n");
for(i=0; i<T->n; i++)
{
printf("%d\t",i);
for(j=0; j<T->n; j++)
{
if(T->edge[i][j]!=0||T->edge[j][i]!=0)
//cout<<T->vertex[i];
printf("1 ");
else
printf("0 ");
}
printf("\n");
}
return;
}
2.邻接表:
void PrintAdjGraph (AdjGraph *G)
{
printf("邻接表打印(PrintAdjGraph)\n");
int flag[11][11]= {0};
int i=0;
EdgeNode *p=(EdgeNode*)malloc(sizeof(EdgeNode));
for(i=0; i<G->n; i++)
{
p=G->vexlist[i].firstedge;
while(p!=NULL)
{
if(flag[i][p->adjvex]==0&&flag[p->adjvex][i]==0)
{
printf("v%d->v%d:(%d,%d):%d\n",i,p->adjvex,i,p->adjvex,p->cost);
flag[i][p->adjvex]=1;
flag[p->adjvex][i]=1;
}
p=p->next;
}
}
//cout<<T->vertex[i];
}
3.邻接多重表:
void PrintInitUDGAMLTrue(AMLGraph *G)
{
printf("输出无向图的邻接多重表G(PrintInitUDGAMLTrue)\n");
int i;
EBox *p=(EBox*)malloc(sizeof(EBox));
for(i=0; i<G->vexnum; i++)
{
p=G->adjmulist[i].firstedge;
//printf("%s :\n",G->adjmulist[i].data);
while(p!=NULL)
{
if(p->mark==0)
{
printf("(%s,%s):%d\n",G->adjmulist[i].data,p->info.vertex,p->info.weight);
p->mark=1;
}
p=p->ilink;
}
}
for(i=0; i<G->vexnum; i++)
{
p=G->adjmulist[i].firstedge;
while(p!=NULL)
{
if(p->mark==1)
p->mark=0;
p=p->ilink;
}
}
return;
}
邻接矩阵到邻接表的转换:
AdjGraph TransMTGraphSquareToAdjGraph(MTGraphSquare *T)//邻接矩阵初始化
{
printf("邻接矩阵到邻接表的转换(TransMTGraphSquareToAdjGraph)\n");
//PrintMTGraphSquare(T);
int flag[11][11]= {0};
AdjGraph G;
int tail,head,weight;
int j,k;
G.n=T->n;
G.e=T->e;//输入顶点个数和边数
for ( int i = 0; i < G.n; i++) //建立顶点表
{
strcpy(G.vexlist[i].vertex,T->vertex[i]); //输入顶点信息
G.vexlist[i].firstedge = NULL;
} //边表置为空表
//逐条边输入,建立边表
for(j=0; j<G.n; j++)
{
for(k=0; k<G.n; k++)
{
if(T->edge[j][k]!=0&&flag[j][k]==0)
{
tail=k;
head=j;
weight=T->edge[j][k];
flag[j][k]=1;
flag[k][j]=1;
EdgeNode *p = (EdgeNode*)malloc(sizeof(EdgeNode)); //建立边结点
p->adjvex = head;
p->cost = weight; //3.3设置边结点
p->next = G.vexlist[tail].firstedge; //链入第 tail 号链表的前端
G.vexlist[tail].firstedge = p;
p = (EdgeNode*)malloc(sizeof(EdgeNode));
p->adjvex = tail;
p->cost = weight;
p->next = G.vexlist[head].firstedge; //链入第 head 号链表的前端
G.vexlist[head].firstedge = p;
//printf("(%d,%d):%d\n",tail,head,weight);
//printf("%d,%d,%d\n",head,tail,weight);
}
}//输入
}
PrintAdjGraph(&G);
return G;
}
接表到邻接矩阵的转换:
MTGraphSquare TransAdjGraphSquareToMTGraph(AdjGraph *G)
{
printf("邻接表到邻接矩阵的转换(TransAdjGraphSquareToMTGraph)\n");
MTGraphSquare T;
int i,j,k,w;
T.n=G->n;
T.e=G->e;
for(i=0; i<T.n; i++)
{
strcpy(T.vertex[i],G->vexlist->vertex);
}
for(i=0; i<T.n; i++)
for(j=0; j<T.n; j++)
T.edge[i][j]=0;
EdgeNode *p;
for(k=0; k<T.n; k++)
{
p=G->vexlist[k].firstedge;
while(p!=NULL)
{
i=p->adjvex;
j=k;
w=p->cost;
T.edge[i][j]=w;
p=p->next;
}//printf("v%d->v%d:(%d,%d):%d\n",i,j,i,j,T->edge[i][j]);
}
PrintMTGraphSquare(&T);
return T;
}
邻接表到邻接多重表的转换:
AMLGraph TransAdjGraphSquareToAMLGraph(AdjGraph *T)
{
AMLGraph G;
printf("邻接表到邻接多重表的转换(TransAdjGraphSquareToAMLGraph)\n");
printf("输入无向图的邻接多重表G(InitUDGAML)\n");
//char v1[5], v2[5];
int v1,v2;
char str[5]="v0";
str[0]='v';
int i, j, weight;
int flag[12][12]= {1};
G.vexnum=T->n;
G.edgenum=T->e;
//printf("debug1\n");
for(i=0; i<12; i++)
for(j=0; j<12; j++)
flag[i][j]=1;
for(i=0; i<G.vexnum; i++) //建立顶点表
{
strcpy(G.adjmulist[i].data,T->vexlist[i].vertex);
G.adjmulist[i].firstedge=NULL;
}
EdgeNode *temp;
//printf("debug2\n");
for(i=0; i<G.vexnum; i++)
{
temp=T->vexlist[i].firstedge;
while(temp!=NULL)
{
//printf("%d %d %d\n",i,temp->adjvex,temp->cost);
if(flag[i][temp->adjvex]||flag[temp->adjvex][i])
{
flag[i][temp->adjvex]=0;
flag[temp->adjvex][i]=0;
v1=i;
v2=temp->adjvex;
weight=temp->cost;
printf("%d %d %d\n",v1,v2,weight);//程序出错竟然是因为%d输出成了%s!!!小错误可能导致大bug!
//i=LocateVex(G,v1);
//j=LocateVex(G,v2);
i=v1;
j=v2;
while(i<0|| i>G.vexnum-1 || j<0 || j>G.vexnum-1)
{
cout<<"结点位置输入错误,重新输入: ";
v1=i;
v2=temp->adjvex;
i=v1;
j=v2;
}
EBox *p=(EBox*)malloc(sizeof(EBox));
p->ivex=i;
p->jvex=j;
p->mark=0;
str[2]='\0';
if(j<10)
str[1]=j+48;
else
strcpy(str,"v10");
strcpy(p->info.vertex,str);
p->ilink=G.adjmulist[i].firstedge;
p->jlink=G.adjmulist[j].firstedge;
p->info.weight=weight;
G.adjmulist[i].firstedge=G.adjmulist[j].firstedge = p;
}
temp=temp->next;
}
}
printf("\n");
PrintInitUDGAMLTrue(&G);
printf("\n");
DisplayAML(&G);
return G;
}
邻接矩阵到邻接多重表的转换:
AMLGraph TransMTGraphSquareToAMLGraph(MTGraphSquare *T)
{
AMLGraph G;
printf("邻接矩阵到邻接多重表的转换(TransMTGraphSquareToAMLGraph)\n");
printf("输入无向图的邻接矩阵T(InitUDGAML)\n");
//char v1[5], v2[5];
int v1,v2;
char str[5]="v0";
str[0]='v';
int i, j, k,x,weight;
int flag[12][12]= {1};
G.vexnum=T->n;
G.edgenum=T->e;
for(i=0; i<12; i++)
for(j=0; j<12; j++)
flag[i][j]=1;
for(i=0; i<G.vexnum; i++) //建立顶点表
{
strcpy(G.adjmulist[i].data,T->vertex[i]);
G.adjmulist[i].firstedge=NULL;
}
for(x=0; x<G.vexnum; x++)
for(k=0; k<G.vexnum; k++)
{
if(T->edge[x][k]!=0&&flag[x][k]&&flag[k][x])
{
v1=x;
v2=k;
flag[x][k]=0;
flag[k][x]=0;
weight=T->edge[x][k];
printf("%d %d %d\n",v1,v2,weight);//程序出错竟然是因为%d输出成了%s!!!小错误可能导致大bug!
i=v1;
j=v2;
while(i<0|| i>G.vexnum-1 || j<0 || j>G.vexnum-1)
{
cout<<"结点位置输入错误,重新输入: ";
if(T->edge[x][k]!=0&&flag[x][k]&&flag[k][x])
{
v1=x;
v2=k;
flag[x][k]=0;
flag[k][x]=0;
weight=T->edge[x][k];
}
i=v1;
j=v2;
}
EBox *p=(EBox*)malloc(sizeof(EBox));
p->ivex=i;
p->jvex=j;
p->mark=0;
str[2]='\0';
if(j<10)
str[1]=j+48;
else
strcpy(str,"v10");
strcpy(p->info.vertex,str);
p->ilink=G.adjmulist[i].firstedge;
p->jlink=G.adjmulist[j].firstedge;
p->info.weight=weight;
G.adjmulist[i].firstedge=G.adjmulist[j].firstedge = p;
}
}
printf("\n");
PrintInitUDGAMLTrue(&G);
printf("\n");
DisplayAML(&G);
return G;
}
邻接多重表到邻接矩阵的转换:
MTGraphSquare TransAMLGraphSquareToMTGraph(AMLGraph *G)
{
printf("邻接多重表到邻接矩阵的转换(TransAMLGraphSquareToMTGraph)\n");
int i,j,k,w;
MTGraphSquare T;
T.n=G->vexnum;
T.e=G->edgenum;
for(i=0; i<T.n; i++)
{
strcpy(T.vertex[i],G->adjmulist[i].data);
}
for(i=0; i<T.n; i++)
for(j=0; j<T.n; j++)
T.edge[i][j]=0;
EBox *p=(EBox*)malloc(sizeof(EBox));
for(i=0; i<G->vexnum; i++)
{
p=G->adjmulist[i].firstedge;
//printf("%s :\n",G->adjmulist[i].data);
while(p!=NULL)
{
//printf("In loop.\n");
if(p->mark==0)
{
k=p->ivex;
j=p->jvex;
w=p->info.weight;
//printf("%d,%d :%d\n",k,j,w);
T.edge[k][j]=w;
p->mark=1;
}
p=p->ilink;
}
}
for(i=0; i<G->vexnum; i++)
{
p=G->adjmulist[i].firstedge;
while(p->ilink!=NULL)
{
if(p->mark==1)
p->mark=0;
p=p->ilink;
}
}
PrintMTGraphSquare(&T);
return T;
}
邻接多重表到邻接表的转换:
//总而言之,就是对于表的遍历和建立两个联合起来。
AdjGraph TransAMLraphSquareToAdjGraph(AMLGraph *T)
{
printf("邻接多重表到邻接表的转换(TransAMLraphSquareToAdjGraph)\n");
int i;
int tail,head,weight;
AdjGraph G;
G.n=T->vexnum;
G.e=T->edgenum;
for(i=0; i<G.n; i++)//建立顶点表
{
strcpy(G.vexlist[i].vertex,T->adjmulist[i].data);//输入顶点信息
G.vexlist[i].firstedge = NULL;//边表置为空表
}
EBox *p=(EBox*)malloc(sizeof(EBox));
for(i=0; i<G.n; i++)
{
p=T->adjmulist[i].firstedge;
//printf("%s :\n",G.adjmulist[i].data);
while(p!=NULL)
{
//printf("In loop.\n");
if(p->mark==0)
{
tail=p->ivex;
head=p->jvex;
weight=p->info.weight;
//printf("%d,%d :%d\n",k,j,w);
p->mark=1;
EdgeNode *q = (EdgeNode*)malloc(sizeof(EdgeNode)); //建立边结点
q->adjvex = head;
q->cost = weight; //3.3设置边结点
q->next = G.vexlist[tail].firstedge; //链入第 tail 号链表的前端
G.vexlist[tail].firstedge = q;
q = (EdgeNode*)malloc(sizeof(EdgeNode));
q->adjvex = tail;
q->cost = weight;
q->next = G.vexlist[head].firstedge; //链入第 head 号链表的前端
G.vexlist[head].firstedge = q;
printf("(%d,%d):%d\n",tail,head,weight);
}
p=p->ilink;
}
}
PrintAdjGraph(&G);
for(i=0; i<T->vexnum; i++)
{
p=T->adjmulist[i].firstedge;
while(p!=NULL)
{
if(p->mark==1)
p->mark=0;
p=p->ilink;
}
}
return G;
}
五、经验体会与不足
其实这些存储结构之间的转换都是很相似的,访问方式和顺序也是相似的,但是具体的存储结构的不同,要具体去写还是会在实际中遇到很多问题。六个表之间的转换其实步骤都是相似的,只是把数据都给读出来,然后按照相应的表储存。
这次的实验中,遇到了一些问题,比如说bfs和dfs用非递归来写,我觉得这个部分对我来说最难,这个过程很难理解,但是最后在室友的帮助下,我顺利解决了这个问题。