题目一: 图的遍历(* 必做题)
实验内容和要求
[问题描述]
对给定图,实现图的深度优先遍历和广度优先遍历。
[基本要求]
以邻接表为存储结构,实现连通无向图的深度优先和广度优先遍历。以用户指定的结点为起点,分别输出每种遍历下的结点访问序列。
【测试数据】
由学生依据软件工程的测试技术自己确定。
主要思想
先用邻接表创建无向图,输入顶点作为表头结点,输入一条边依附的两个顶点生成边结点。深度优先遍历类似于树的中序遍历,先访问左孩子,再访问根结点,最后访问右孩子,使用递归方法实现。广度优先搜索类似于树的层次遍历,使用队列实现。设立一个标记数组,标记第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;
}