实验四——图的基本操作及应用

题目一: 图的遍历(* 必做题)

实验内容和要求

[问题描述]

          对给定图,实现图的深度优先遍历和广度优先遍历。

[基本要求]

   以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。

【测试数据】
  由学生依据软件工程的测试技术自己确定。

主要思想

    先用邻接表创建无向图,输入顶点作为表头结点,输入一条边依附的两个顶点生成边结点。深度优先遍历类似于树的中序遍历,先访问左孩子,再访问根结点,最后访问右孩子,使用递归方法实现。广度优先搜索类似于树的层次遍历,使用队列实现。设立一个标记数组,标记第i个结点是否被访问过,依次检查被访问结点的所有邻接点,如果没有被访问过则将其压入队列,最终所有的结点都会出入依次队列,队列成空时代表所有结点都已被访问过。

调试分析

我在写广度优先遍历时没有沉着思考,想着用两个队列进行模拟,实现时遇到许许多多的问题。当看到别人用一个队列完美解出来的时候就像如梦初醒。知识还是需要多多运用才能灵活掌握。

代码实现

#include <iostream>
#include<queue>;
#include<cstring>
using namespace std;
#define MVNum 100
#define Status int
#define OK 1
queue<int>q;
bool visited[MVNum]={false};//初始化访问数组
typedef struct ArcNode{//边结点
	int adjvex;//边所指向的顶点位置
	struct ArcNode *nextarc;//指向下一条边的指针
}ArcNode;
typedef struct VNode{//顶点信息
	int data;
	ArcNode *firstarc;//指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];
typedef struct ALGraph{//邻接表
	AdjList vertices;
	int vexnum,arcnum;//图的当前顶点数和边数
}ALGraph;
int LocateVex(ALGraph G,int v){//确定v1和v2在G中的位置,即顶点在G.vertices中的序号
	for(int i=0;i<G.vexnum;i++){
		if(G.vertices[i].data==v)
			return i;
	}
}
Status CreateUDG(ALGraph &G)//邻接表创建无向图
{
	cin>>G.vexnum>>G.arcnum;
	for(int i=0;i<G.vexnum;i++)//输入各点,构建表头结点表
	{
		cin>>G.vertices[i].data;//输入顶点值
		G.vertices[i].firstarc=NULL;//初始化表头结点的指针域为NULL
	}
	for(int k=0;k<G.arcnum;++k)
	{
		int v1,v2;
		cin>>v1>>v2;//输入一条边依附的两个顶点
		int i=LocateVex(G,v1);//确定两个顶点在图中的位置
		int j=LocateVex(G,v2);
		ArcNode *p1,*p2;
		p1=new ArcNode;//生成一个新的边结点
		p1->adjvex=j;
		p1->nextarc=G.vertices[i].firstarc;//插入vi的边表表头
		G.vertices[i].firstarc=p1;
		p2=new ArcNode;//生成对称的新的边结点
		p2->adjvex=i;
		p2->nextarc=G.vertices[j].firstarc;//插入vj的边表表头
		G.vertices[j].firstarc=p2;
	}
	return OK;
}
void DFS_AL(ALGraph G,int v){//深度优先遍历
	cout<<G.vertices[v].data<<' ';
	visited[v]=true;
	ArcNode *p;
	int w;
	p=G.vertices[v].firstarc;
	while(p!=NULL){
		w=p->adjvex;//w是v的邻接点
		if(!visited[w])//如果w未访问,则递归调用DFS_AL
			DFS_AL(G,w);
		p=p->nextarc;//p指向下一个边结点
	}
}
int FirstAdjVex(ALGraph G,int u){//找到u的第一个邻接点
	ArcNode *p;
	p=G.vertices[u].firstarc;//2
	int a=p->adjvex;//2
	return a;
}
int NextAdjVex(ALGraph G,int u,int w){//找到u相对于w的下一个邻接点
	ArcNode *p;
	p=G.vertices[u].firstarc;
	int a=p->adjvex;
	while(w!=a){
		p=p->nextarc;
		a=p->adjvex;
	}
	if(p->nextarc!=NULL){
        p=p->nextarc;
        a=p->adjvex;
        return a;
	}
	else
        return -1;
}
void BFS(ALGraph G,int v){//广度优先遍历
	memset(visited,false,100);
	cout<<endl<<G.vertices[v].data<<' ';
	visited[v]=true;
	q.push(v);//将第v个结点压入队列
	int u,w;
	while(!q.empty()){//队列为空时跳出循环
		u=q.front();//取队头元素,赋值给u
		q.pop();//队头元素出队
		for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w)){//依次检查u的所有邻接点
			if(!visited[w])//w为u的尚未访问过的结点
			{
				cout<<G.vertices[w].data<<' ';
				visited[w]=true;
				q.push(w);
			}
		}
	}
}
int main(){
	ALGraph G;
	CreateUDG(G);
	DFS_AL(G,0);
	BFS(G,0);
	return 0;
}

题目二:最短路径问题(***)

实验内容和要求

[问题描述]

  给定一个无向网,可以求得任意一对顶点之间的最短路径。

[基本要求]

   以邻接矩阵为存储结构,实现弗洛伊德算法求解每一对顶点之间的最短路径及最短路径长度。

[测试数据]

由学生依据软件工程的测试技术自己确定。

主要思想

使用邻接矩阵创建无向网,用两个二维数组分别保存点与点之间的最短路径及最短路径长度,其中最短路径即是记录j点的前驱。依次输入点的信息,一条边依附的顶点和权值来构造邻接矩阵。用弗洛伊德算法求最短路径,先初始化各对之间初始已知路径及距离,如果i和j之间有弧,则将j的前驱置为i,如果i和j之间无弧,则将j的前驱置为-1。如果从i经k到j的一条路径更短,则更新最短路径长度,更改j的前驱为k。

调试分析

在初始化邻接矩阵的时候遇到一些问题,没有将i与j相等的情况处理好,导致程序出现漏洞,今后考虑问题要全面。

#include<iostream>//最短路
using namespace std;
#define MaxInt 32767
#define MVNum 100
#define Status int
#define OK 1
int D[MVNum][MVNum];//最短路径长度
int path[MVNum][MVNum];//最短路径
typedef struct{
    int vexs[MVNum];
    int arcs[MVNum][MVNum];
    int vexnum,arcnum;
}AMGragh;
int LocateVex(AMGragh G,int v){//确定v1和v2在G中的位置,即顶点在G.vertices中的序号
	for(int i=0;i<G.vexnum;i++){
		if(G.vexs[i]==v)
			return i;
	}
}
Status CreateUDN(AMGragh &G){//创建无向网
    cin>>G.vexnum>>G.arcnum;
    for(int i=0;i<G.vexnum;++i)//依次输入点的信息
        cin>>G.vexs[i];
    for(int i=0;i<G.vexnum;i++)//初始化邻接矩阵,边的权值
        for(int j=0;j<G.vexnum;j++)
            {
                G.arcs[i][j]=MaxInt;//均置为极大值
                if(i==j)
                    G.arcs[i][j]=0;//i与j相等初始化为0
            }
    for(int k=0;k<G.arcnum;++k){
        int v1,v2,w;
        cin>>v1>>v2>>w;//输入一条边依附的顶点和权值
        int i=LocateVex(G,v1);//确定v1和v2的位置
        int j=LocateVex(G,v2);
        G.arcs[i][j]=w;//边及其对称边的权值置为w
        G.arcs[j][i]=w;
    }
    return OK;
}
void Floyd(AMGragh G){//弗洛伊德算法
    int i,j,k;
    for(i=0;i<G.vexnum;++i)//初始化各对之间初始已知路径及距离
        for(j=0;j<G.vexnum;j++){
            D[i][j]=G.arcs[i][j];
            if(D[i][j]<MaxInt&&i!=j)//如果i和j之间有弧,则将j的前驱置为i
                path[i][j]=i;
            else
                path[i][j]=-1;//如果i和j之间无弧,则将j的前驱置为-1
        }
    for(k=0;k<G.vexnum;k++)
        for(i=0;i<G.vexnum;++i)
            for(j=0;j<G.vexnum;j++)
                if(D[i][k]+D[k][j]<D[i][j]){//从i经k到j的一条路径更短
                    D[i][j]=D[i][k]+D[k][j];//更新D[i][j]
                    path[i][j]=path[k][j];//更改j的前驱为k
                }
}
int main(){
    AMGragh G;
    CreateUDN(G);
    Floyd(G);
    cout<<"最短路径长度为:"<<endl;
    for(int i=0;i<G.vexnum;++i)
    {   for(int j=0;j<G.vexnum;j++)
            cout<<"<"<<i<<","<<j<<">"<<" : "<<D[i][j]<<endl;
    }
    cout<<"最短路径为:"<<endl;
    for(int i=0;i<G.vexnum;++i)
    {   for(int j=0;j<G.vexnum;j++)
            cout<<"<"<<i<<","<<j<<">"<<" : "<<path[i][j]<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/DEAR_CXN/article/details/86583651