20182330 2019-2020-1 《数据结构与面向对象程序设计》实验九报告
课程:《程序设计与数据结构》
班级: 1823
姓名: 魏冰妍
学号:20182330
实验教师:王志强
实验日期:2019年12月2日
必修/选修: 必修
1.实验内容
完成图的综合实践
(1)初始化:根据屏幕提示(例如:输入1为无向图,输入2为有向图)初始化无向图和有向图(可用邻接矩阵,也可用邻接表),图需要自己定义(顶点个数、边个数,建议先在草稿纸上画出图,然后再输入顶点和边数)
(2)图的遍历:完成有向图和无向图的遍历(深度和广度优先遍历)
(3)完成有向图的拓扑排序,并输出拓扑排序序列或者输出该图存在环
(4)完成无向图的最小生成树(Prim算法或Kruscal算法均可),并输出
(5)完成有向图的单源最短路径求解(迪杰斯特拉算法)
2. 实验过程及结果
1.初始化:根据屏幕提示(例如:输入1为无向图,输入2为有向图)初始化无向图和有向图(可用邻接矩阵,也可用邻接表),图需要自己定义(顶点个数、边个数,建议先在草稿纸上画出图,然后再输入顶点和边数)
public Sorting(char[] dingdian, EData[] bian) {
int lenv = dingdian.length;
int elen = bian.length;
// 初始化顶点
mV= new N[lenv];
for (int i = 0; i < mV.length; i++) {
mV[i] = new N();
mV[i].dingdian = dingdian[i];
mV[i].firstX = null;
}
// 初始化边
Enum = elen;
for (int i = 0; i < elen; i++) {
// 读取顶点
char c1 = bian[i].start;
char c2 = bian[i].end;
int weight = bian[i].weight;
int p1 = gPs(c1);
int p2 = gPs(c2);
B node1 = new B ();
node1.i = p2;
node1.w = weight;
//连接
if(mV[p1].firstX == null)
mV[p1].firstX = node1;
else
Connect(mV[p1].firstX, node1);
B node2 = new B ();
node2.i = p1;
node2.w = weight;
//连接
if(mV[p2].firstX == null)
mV[p2].firstX = node2;
else
Connect(mV[p2].firstX, node2);
}
}
2.图的遍历:完成有向图和无向图的遍历(深度和广度优先遍历)
- 深度优先遍历
private void DFS(int i, boolean[] BL) {
B node;
BL[i] = true;
System.out.printf("%c ", mV[i].dingdian);
node = mV[i].firstX;
while (node != null) {
if (!BL[node.i])
DFS(node.i, BL);
node = node.nextX;
}
}
- 广度优先遍历
public void BFS() {
int head = 0;
int rear = 0;
int[] queue = new int[mV.length]; // 辅组队列
boolean[] BL = new boolean[mV.length]; // 顶点访问标记
for (int i = 0; i < mV.length; i++)
BL[i] = false;
System.out.printf("广度优先遍历: ");
for (int i = 0; i < mV.length; i++) {
if (!BL[i]) {
BL[i] = true;
System.out.printf("%c ", mV[i].dingdian);
queue[rear++] = i; // 入队列
}
while (head != rear) {
int j = queue[head++]; // 出队列
B node = mV[j].firstX;
while (node != null) {
int k = node.i;
if (!BL[k])
{
BL[k] = true;
System.out.printf("%c ", mV[k].dingdian);
queue[rear++] = k;
}
node = node.nextX;
}
}
}
System.out.printf("
");
}
3.完成有向图的拓扑排序,并输出拓扑排序序列或者输出该图存在环
public int TpSort() {
int index = 0;
int num = mV.length;
int[] ins; // 入度数组
char[] tops;
Queue<Integer> queue;
ins = new int[num];
tops = new char[num];
queue = new LinkedList<Integer>();
// 统计每个顶点的入度数
for(int i = 0; i < num; i++) {
B node = mV[i].firstX;
while (node != null) {
ins[node.i]++;
node = node.nextX;
}
}
// 将所有入度为0的顶点入队列
for(int i = 0; i < num; i ++)
if(ins[i] == 0)
queue.offer(i); // 入队列
while (!queue.isEmpty()) { // 队列非空
int j = queue.poll().intValue(); // 出队列。j是顶点的序号
tops[index++] = mV[j].dingdian;
B node = mV[j].firstX;
while(node != null) {
// 入度减1。
ins[node.i]--;
// 若入度为0,则入队列
if( ins[node.i] == 0)
queue.offer(node.i); // 入队列
node = node.nextX;
}
}
if(index != num) {
System.out.printf("有向有环图
");
return 1;
}
// 打印拓扑排序结果
System.out.printf("拓扑排序: ");
for(int i = 0; i < num; i ++)
System.out.printf("%c ", tops[i]);
System.out.printf("
");
return 0;
}
- 完成无向图的最小生成树(Prim算法或Kruscal算法均可),并输出
- Kruscal算法
public void kruskal() {
int index = 0;
int[] v = new int[Enum]; // 保存终点。
EData[] rets = new EData[Enum]; // 暂存结果数组
EData[] e; // 对应的所有边
e = getEdges();
// 将边按权排序
sortEdges(e, Enum);
for (int i=0; i<Enum; i++) {
int p1 = gPs(e[i].start);
int p2 = gPs(e[i].end);
int m = getEnd(v, p1);
int n = getEnd(v, p2);
// 如果m!=n,则没有形成环路
if (m != n) {
v[m] = n;
rets[index++] = e[i];
}
}
}
5.完成有向图的单源最短路径求解(迪杰斯特拉算法)
public void dijkstra(int s, int[] q, int[] t) {
// flag[i]=true表示最短路径已成功获取。
boolean[] flag = new boolean[mV.length];
// 初始化
for (int i = 0; i < mV.length; i++) {
flag[i] = false;
q[i] = 0; // 顶点i的前驱顶点为0。
t[i] = getWeight(s, i);
}
// 初始化
flag[s] = true;
t[s] = 0;
int k = 0;
for (int i = 1; i < mV.length; i++) {
// 寻找当前最小的路径;
// 寻找当前最小的路径;
// 寻找当前最小的路径;
int min = INF;
for (int j = 0; j < mV.length; j++) {
if (flag[j]==false && t[j]<min) {
min = t[j];
k = j;
}
}
// 获取到最短路径
flag[k] = true;
for (int j = 0; j < mV.length; j++) {
int tmp = getWeight(k, j);
tmp = (tmp==INF ? INF : (min + tmp)); // 防止溢出
if (flag[j]==false && (tmp<t[j]) )
{
t[j] = tmp;
q[j] = k;
}
}
}
- 实验结果截图
3. 实验过程中遇到的问题和解决过程
-
问题1:try异常导致程序锁死。
-
问题1解决方案:解决时发现不止我一个人有这个问题。参照博客发现是
e.printStackTrace()
。于是删掉 e.printStackTrace() ,异常处理。
短时间内大量请求访问此接口 -> 代码本身有问题,很多情况下抛异常 -> e.printStackTrace() 来打印异常到控制台 -> 产生错误堆栈字符串到字符串池内存空间 -> 此内存空间一下子被占满了 -> 开始在此内存空间产出字符串的线程还没完全生产完整,就没空间了 -> 大量线程产出字符串产出到一半,等在这儿(等有内存了继续搞啊)-> 相互等待,等内存,锁死了,整个应用挂掉了。
其他(感悟、思考等)
最后一个小实验,个人认为图的理解比树简单一点,并且可以利用到离散中学过的知识。java结课意味着接下来可以安心复习期末和准备app了。