数据结构实验题:
实验一:编写一个程序exp8-10.cpp,设计相关算法完成以下功能。
①输出如果8.56所示的有向图G从顶点5到顶点2的所有简单路径。
②输出如图8.56所示的有向图G从顶点5到顶点2的所有长度为3的简单路径。
③输出如图8.56所示的有向图G从顶点5到顶点2的最短路径。
#include<iostream>
#include<vector>
using namespace std;
#define MAXV 20//定义最大结点数
#define Node 6
//1.输出所有有向图G从顶点5到顶点2的所有简单路径
//2.输出有向图G从顶点5到顶点2的所有长度为3的简单路径
//3.输出有向图G从顶点5到顶点2的最短路径
typedef struct
{
int data;//顶点编号
int parent;//前一个顶点的位置
} QUERE;
typedef struct ANode
{
int adjvex;//该边的终点编号
struct ANode *nextarc;//指向下一条边的指针
} ArcNode;//边结点类型
typedef struct VNode
{
int data;//顶点信息
ArcNode *firstarc;//指向第一条边
} VNode;//邻接表头结点类型
typedef VNode AdjList[MAXV];//AdjList是邻接表类型
typedef struct
{
AdjList adjlist;//邻接表
int n,e;//图中的顶点数n和边数e
} ALGraph;//完整的图邻接表类型
class Search_path {
private:
vector<int> visited;
vector<ArcNode*>for_clean;
public:
Search_path()
{
visited.resize(MAXV,0);//重新扩容,默认没有访问过
}
ALGraph* CreateGraph(int border[][Node])
{
int row = Node;//表示的是顶点个数
int line = 0;//表示的是边的数目
ALGraph *G;
ArcNode *p;
G = (ALGraph *)malloc(sizeof(ALGraph));//分配内存空间
for(int i = 0;i < row;i++)
{
G->adjlist[i].firstarc = NULL;
}
for(int i = 0;i < row;i++)//采用头插法建表
for(int j = row - 1;j >= 0; j--)
if(border[i][j] == 1)
{
p = (ArcNode*)malloc(sizeof(ArcNode));//创建一个结点*p
p->adjvex = j;
p->nextarc = G->adjlist[i].firstarc;//采用头插法插入*p
G->adjlist[i].firstarc = p;
for_clean.push_back(p);
line++;
}
G->n = row;//顶点数
G->e = line;//边数
return G;
}
void Graph_Free(ALGraph *g)//释放内存空间
{
free(g);
}
void DFS(ALGraph *G, int v)//深度优先遍历
{
ArcNode *p;
visited[v] = 1;//置已访问标记
printf(" %d ",v);//输出被访问顶点的编号
p = G->adjlist[v].firstarc;//p指向顶点v的第一个邻接点
while(p!=NULL)
{
if(visited[p->adjvex]==0)//若p->adjvex顶点未被访问过,递归访问它
{
DFS(G,p->adjvex);
}
p = p->nextarc;//p指向顶点v的下一个邻接点
}
}
void FindPath(ALGraph *G,int u, int v,vector<int> path, int d=-1)
//其中d表示path中的路径长度,初始化为-1
{
int w, i;
ArcNode *p;
d++;path[d] = u;//路径长度d增1,顶点u加入到路径中
visited[u] = 1;//置已访问路径
if(u == v&&d>=1)
{
for(i=0;i<=d;i++)
{
printf("%2d",path[i]);
}
printf("\n");//找到一条路径则输出
}
p = G->adjlist[u].firstarc;//p指向顶点u的第一个相邻点
while(p!=NULL)
{
w = p->adjvex;//w为顶点u的相邻顶点
if(visited[w] == 0)
{
FindPath(G,w,v,path,d);
}
p = p->nextarc;
}
visited[u] = 0;//恢复环境该顶点可以重新使用,回溯算法的思想
}
void PathAll(ALGraph *G, int u, int v, vector<int> path,int d=-1)
{
int w,i;
ArcNode *p;
visited[u] = 1;
d++;path[d] = u;//路径长度d自增1,顶点u加入到路径中
if(u==v&&d==3)//输出一条路径
{
for(i = 0;i<=d;i++)
{
printf(" %d ",path[i]);
}
printf("\n");
}
p = G->adjlist[u].firstarc;//p指向顶点u的第一个邻接点
while(p!=NULL)
{
w = p->adjvex;//w为u的邻接点
if(visited[w] == 0)//若该顶点未标记则递归访问之
{
PathAll(G,w,v,path,d);
}
p = p->nextarc;//p指向顶点u的下一个相邻点
}
visited[u] = 0;//恢复环境,使该顶点可以重新使用
}
void ShortPath(ALGraph *G, int u, int v)
{
//输出从顶点u到顶点v的最短路径
ArcNode *p;
int w, i;
QUERE qu[MAXV];//非环形队列
int front = -1, rear = -1;//队列的头,尾指针
vector<int> path(MAXV);
for(i = 0;i<G->n;i++)//访问标记置初值0
{
visited[i] = 0;
}
rear++;
qu[rear].data = u;
qu[rear].parent = -1;
visited[u] = 1;//顶点u进队,表示已经访问过
while(front!=rear)//队不空时循环
{
front++;//出队顶点w
w = qu[front].data;
if(w == v)//找到v时输出路径之逆路径
{
i = front;
while (qu[i].parent != -1)
{
printf("%2d",qu[i].data);
i = qu[i].parent;
}
printf("%2d\n",qu[i].data);
break;
}
p = G->adjlist[w].firstarc;//找到w的第一个邻接点
while(p!=NULL)
{
if(visited[p->adjvex] == 0)
{
visited[p->adjvex] = 1;
rear++; //将w的未访问过的邻接点进队
qu[rear].data = p->adjvex;
qu[rear].parent = front;
}
p = p->nextarc;//找w的下一个邻接点
}
}
}
};
int main()
{
Search_path solution;
int choose;
ALGraph* new_graph;
vector<int> path(MAXV);
int border[Node][Node] = {
{0,1,0,1,0,0},
{0,0,1,0,0,0},
{1,0,0,0,0,1},
{0,0,1,0,0,1},
{0,0,0,1,0,0},
{1,1,0,1,1,0}};
new_graph = solution.CreateGraph(border);
printf("请选择需要使用的功能:\n1.查找所有从顶点5到顶点2的简单路径\n");
printf("2.输出有向图G从顶点5到顶点2所有长度为3的简单路径\n");
printf("3.输出有向图G从顶点5到顶点2的最短路径\n");
printf("4.打印图\n");
scanf("%d",&choose);
printf("结果为\n");
switch(choose)
{
case 1:solution.FindPath(new_graph,5,2,path);break;
case 2:solution.PathAll(new_graph,5,2,path);break;
case 3:solution.ShortPath(new_graph,5,2);break;
case 4:solution.DFS(new_graph,0);break;
default:
printf("没有找到所需的功能\n");
}
solution.Graph_Free(new_graph);
return 0;
}
实验结果:
实验一中构建关于存储图所使用的数据结构一开始我使用的邻接矩阵,后来发现邻接矩阵应用于查找上不如邻接表方便,因此修改为了邻接表,对于邻接表这种数据结构不是很熟悉。图的存储所用的数据结构比树更加复杂,要多使用才能熟悉。
实验一中第一个要求求两点间所有简单路径使用的是回溯法,而第二个要求求两点间长度为3的简单路径和就和第一个要求大同小异了,加一个判断语句在已到达终点的路径中如果路径长度为3的路径就输出。第三个要求最短路径,使用的是DFS,后来我发现要求一已经求出了所有路径,可以直接输出要求一中最短路径,DFS时间复杂度低。第三个要求中输出最短路径是反序输出结果的,在到达终点后,通过终点的结果往回找到起点,结果不是线性存储的,还没有找到改为正序输出的途径。