一、项目目的
1、掌握图的相关概念;
2、掌握图的存储结构;
3、掌握图的遍历算法;
4、掌握图的应用。
二、实验内容
设计有N个公园景点的平面图,为来访参观游玩的客人提供时间最省的优质服务。(设计公园导游咨询的模拟程序)
- 采用邻接表或邻接矩阵存储结构;
- 可以查询任意两个景点间的最短路径;
- 尝试求解遍历全部景点时间最省的程序。
- 用例测试运行程序。
注:景点个数,名称,权值自定。
三、实验要求
1、实验报告要求用Java语言实现,2或3人一组。
2、完成“数据结构项目情境实验报告”。
3、完成项目程序代码的编写,并能正确运行
四、开发环境及人员分工
集成开发环境(IDE) | Eclipse JAVA |
项目成员 | 分工 |
五、实现过程详细说明
1.采用邻接表或邻接矩阵存储结构,掌握图的相关概念;
2.可以查询任意两个景点间的最短路径,掌握图的存储结构;
3.尝试求解遍历全部景点时间最省的程序,掌握图的遍历算法。
六、实验总结
过而能改,善莫大焉。在课程设计过程中,我们不断发现错误,不断改正,不断领悟,不断获龋最终的检测调试环节,本身就是在践行过而能改,善莫大焉的知行观。机器是比任何教师更严厉的检查者。因此,在数据结构的学习过程中,必须严格按照老师的要求,主动地、积极地、认真地做好每一个实验,以不断提高自己的编程能力与专业素质。
七、代码实现(程序粘贴,运行结果截图)
邻接矩阵图Dijkstra算法:
public void Dijkstra(String name) {
int v = findByName(name);
dist = new int[numOfVertex];//存储最短距离数组
pre = new int[numOfVertex];//前驱顶点数组
for (int i = 0; i < numOfVertex; i++) {
//初始化,距离数组(dist)变为起点直接到该点的距离,
//前驱数组(pre)全变为-1,
//遍历数组(isVisit)变为false代表没有被遍历
isVisit[i] = false;
dist[i] = Edge[v][i];
if (dist[i] < MAX) {pre[i] = v;} else { pre[i] = -1;}}
dist[v] = 0;//起点到自身距离为0
isVisit[v] = true;
for (int i = 0; i < numOfVertex - 1; i++) {
//循环次数为顶点个数,松弛(顶点个数-1)次,
//每次循环确定一个点,表示起点到该点最短距离确定(除起点)
int min = MAX;//记录最短路径的距离
int u = v;//记录最短路径的终点
for (int j = 0; j < numOfVertex; j++) {
//此循环寻找最短的路径和终点坐标
//贪心算法,找路径最短的并加入最短距离构造数组,
if (isVisit[j] == false && dist[j] < min) {
//如果小于min且最短距离未被找到,替代,并记录终点下标
u = j;
min = dist[j];
}}isVisit[u] = true;//最短的路径终点的最短路径找到for (int k = 0; k < numOfVertex; k++) {
//此循环判断,先经过该点再到其他点,距离是否会变短,
//若变短,更新距离
int w = getWeight(u, k);//获取u到k路径长
if (isVisit[k] == false && w < MAX && dist[u] + w < dist[k]) {//若该点最短距离未被找到,判断是否能松弛//判断v直接到k距离短,和v到u再到k距离哪个短
dist[k] = dist[u] + w;
pre[k] = u; } }}
printPath(v);//打印路径}private void printPath(int v) {
for (int i = 0; i < numOfVertex; i++) {
LinkedList d = new LinkedList();//用链表存储路径
if (i != v) {//当顶点不等于起点,继续打印路径
System.out.print(Vertex[v] + "-->");
d.add(Vertex[i]);
int dan = pre[i];//获取前驱顶点下标
while (dan != v) {//
d.add(Vertex[dan]);//将前驱下标顶点信息加入链表
dan = pre[dan];//找前驱的前驱
}
for (int j = d.size(); j > 0; j--) {//链表正序存储反的路径,则逆序打印路径
if (j != 1) {
System.out.print(d.get(j - 1) + "-->");} else {System.out.print(d.get(j - 1) + ":" + dist[i]);} }System.out.println(); } }}
测试代码:
public class Main {
public static void main(String[] args) {
Graph g = new Graph(20);
g.insertVertex("A");
g.insertVertex("B");
g.insertVertex("C");
g.insertVertex("D");
g.insertVertex("E");
g.insertEdge("A", "B", 2);
g.insertEdge("A", "C", 5);
g.insertEdge("A", "D", 1);
g.insertEdge("C", "D", 1);
g.insertEdge("C", "B", 3);
g.insertEdge("D", "E", 9);
g.insertEdge("E", "B", 10);
g.insertEdge("E", "C", 1);
g.Dijkstra("A");;}邻接链表:
public void Dijkstra(String name) {
pre =new int [numVertex];//初始化构造数组,数组长度为顶点个数
dist =new int [numVertex];
int v = findNum(name);
inti(v);//初始化三个数组
LinkedList<Integer> Q = new LinkedList();//未操作顶点集for(int i=0;i<numVertex;i++){//将所有顶点加入Q//表示所以顶点最短路径都还没被找到
Q.add(i);//顶点下标加入链表
}hile(!Q.isEmpty()) {//Q不空代表,最短路径并未全被找到
int u = MIN(Q);//Min找最短路径,并返回终点下标
//获取u后,开始松弛操作,与u相邻的顶点才能松弛成功
//所有获取以u相接的边
LinkedList <Edge> list = Edges[u];//获取与u相邻的边集
while(!list.isEmpty()) {//当list不空,继续松弛操作relax(list.pop());//松弛操作函数,pop将此边退出}}show();//输出函数}
public void show() {//打印函数
Stack<Integer>[] routes = new Stack[numVertex];//利用栈先进后和前驱顶点是从后向前读取的,
//栈数组依次存储对应顶点的最短路径经过顶点
for(int i = 0;i<numVertex;i++) {//将对应顶点的前驱顶点依次加入数组
routes[i] = new Stack();
int j = i;
while (j != -1) {//不等于-1,表示未到起点
routes[i].push(j);//将当前的前驱顶点加入到栈中
j = pre[j];//获取上一个前驱顶点
}while (!routes[i].isEmpty()) {//输出int k = routes[i].pop();
if(routes[i].size()==1) {
System.out.print(vertex[k].name);
}else { System.out.print("-->" + vertex[k].name);}}
if(dist[i]==MAX) {
System.out.print("无法到达");
}else {
System.out.print(":"+dist[i]);}
System.out.println();}
private void relax(Edge edge) {//松弛操作函数
int v1 = findNum(edge.Start.name);//获取起点下标
int v2 = findNum(edge.End.name);//获取终点下标
int w = edge.getWeight();//获取该边权重
if(dist[v2]>dist[v1]+w) {//若经过该边到v2更短,则松弛成功
dist[v2] = dist[v1]+w;//更新dist数组
pre[v2] = v1;//该边前驱节点}}
private int MIN(LinkedList<Integer> q) {//找dist里最小的路径
if(q.isEmpty()) {return -1;}
int min = q.getFirst();//获取还为找到最短路径的其中一个顶点
for(int i = 0;i<q.size();i++) {//与Q中剩下的顶点依次比较对应的dist数组里的值
int v = q.get(i);if(dist[min]>dist[v]) {//依次比较min = v;}}
q.remove(q.indexOf(min));
return min;}private void inti(int v) {
for(int i = 0;i <numVertex;i++) {dist[i] = MAX;
pre[i] = -1;isVisit[i] = false; }dist[v] = 0;}
多源最短路径(邻接矩阵):public void Floyd() {
distance = Edge;//复制邻接矩阵
for (int k = 0; k < numOfVertex; k++) {//k个顶点,依次对各点松弛
for (int i = 0; i < numOfVertex; i++) {//松弛i行
for (int j = 0; j < numOfVertex; j++) {//松弛j列
distance[i][j] = Math.min(distance[i][j], distance[i][k] + distance[k][j]);
//更新distance数组,松弛成功获取后一结果
//distance[i][k] + distance[k][j]-->i到k到j}}}
for (int i = 0; i < numOfVertex; i++) {//输出distance数组
System.out.print("节点" + (i + 1) + " 的最短路径");
for (int j = 0; j < numOfVertex; j++) {
if(distance[i][j] == Integer.MAX_VALUE/2) {System.out.print("MAX" + " ");
}else {System.out.print(distance[i][j] + " ");}}System.out.println();}}
测试代码public class Main {
public static void main(String[] args) {
Graph g = new Graph(20);g.insertVertex("A");g.insertVertex("B");g.insertVertex("C");
g.insertVertex("D");g.insertVertex("E");g.insertEdge("A", "B", 2);g.insertEdge("A", "C", 5);
g.insertEdge("A", "D", 1);g.insertEdge("C", "D", 1);g.insertEdge("C", "B", 3);
g.insertEdge("D", "E", 9);g.insertEdge("E", "B", 10);g.insertEdge("E", "C", 1);g.Floyd();}}