博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

# 20202304 2021-2022-1 《数据结构与面向对象程序设计》实验九报告

课程:《程序设计与数据结构》
班级: 2023
姓名: 何锐
学号:20202304
实验教师:王志强
实验日期:2021年12月16日

必修/选修: 必修

一、实验内容

(1) 初始化:根据屏幕提示(例如:输入1为无向图,输入2为有向图)初始化无向图和有向图(可用邻接矩阵,也可用邻接表),图需要自己定义(顶点个数、边个数,建议先在草稿纸上画出图,然后再输入顶点和边数)(2分)
(2) 图的遍历:完成有向图和无向图的遍历(深度和广度优先遍历)(4分)
(3) 完成有向图的拓扑排序,并输出拓扑排序序列或者输出该图存在环(3分)
(4) 完成无向图的最小生成树(Prim算法或Kruscal算法均可),并输出(3分)
(5) 完成有向图的单源最短路径求解(迪杰斯特拉算法)(3分)

二、实验过程及结果

(1) 初始化:根据屏幕提示(例如:输入1为无向图,输入2为有向图)初始化无向图和有向图(可用邻接矩阵,也可用邻接表),图需要自己定义(顶点个数、边个数,建议先在草稿纸上画出图,然后再输入顶点和边数)(2分)

我在这里使用了邻接表:(邻接表用自己定义的边和点进行了实现,如果换成邻接矩阵的话用一组二维数组就可以)

选取图为:

 

带权无向图为:

 

 

 (直接截图考试图好吧hhh)

实现代码:(第一部分 只到初始化完毕,另外一提,在实现有向图的初始化的同时便将出入度的计算也完成了)

class edge{//边 node代表构成边的节点,该类为邻接表中
    int node ;//另一个点
    int weight;//权重
    edge nextedge;//节点有多条边,构成链表
}
class point{//点(其中出入度只对有向图进行了实现)
    int pname;//编号
    edge edgehead;//头指针(边链表)
    int in=0;//入度
    int out=0;//出度
}
public class mymap {
    public point[] points;
    private boolean isDirected;//是否有向图,true是有向图(如果实现题目中的一二可以从main函数里做处理)
    public int[][] inmap;//第一个数组量存放该点,第二个量则是给他入入度的点

    mymap(int ps[], int[][] edges, boolean isDirected) {
        inmap = new int[ps.length+1][ps.length+1];
        //ps包含各顶点的编号,若有n个顶点,顶点的编号范围是0~n-1
        //edges是一个n×3的数组,,边的权值等于edges[i][2],若为有向图,那么edges[i][0]指向edges[i][1]
        points = new point[ps.length];
        this.isDirected = isDirected;
        if (isDirected == false) {//无向图的初始化
            for (int j = 0; j < ps.length; j++) {
                points[j] = new point();
                points[j].pname = ps[j];
                edge cur = null;
                for (int i = 0; i < edges.length; i++) {
                    if (edges[i][0] == ps[j]) {
                        if (points[j].edgehead == null) {
                            points[j].edgehead = new edge();
                            points[j].edgehead.node = edges[i][1];
                            points[j].edgehead.weight = edges[i][2];
                            cur = points[j].edgehead;
                        } else {
                            while (cur.nextedge != null) cur = cur.nextedge;
                            cur.nextedge = new edge();
                            cur = cur.nextedge;
                            cur.node = edges[i][1];
                            cur.weight = edges[i][2];
                        }
                    } else if (edges[i][1] == ps[j]) {
                        if (points[j].edgehead == null) {
                            points[j].edgehead = new edge();
                            points[j].edgehead.node = edges[i][0];
                            points[j].edgehead.weight = edges[i][2];
                            cur = points[j].edgehead;
                        } else {
                            while (cur.nextedge != null) cur = cur.nextedge;
                            cur.nextedge = new edge();
                            cur = cur.nextedge;
                            cur.node = edges[i][0];
                            cur.weight = edges[i][2];
                        }
                    }
                }
            }
        } else {//有向图的初始化
            for (int j = 0; j < ps.length; j++) {
                points[j] = new point();
                points[j].pname = ps[j];
            }
            for (int j = 0; j < ps.length; j++) {
                edge cur = null;
                for (int i = 0; i < edges.length; i++) {
                    if (edges[i][0] == ps[j]) {
                        if (points[j].edgehead == null) {
                            points[j].edgehead = new edge();
                            points[j].edgehead.node = edges[i][1];
                            points[j].edgehead.weight = edges[i][2];
                            points[edges[i][0]].out++;
                            points[edges[i][1]].in++;
                            inmap[edges[i][1]][edges[i][0]] = 1;
                            cur = points[j].edgehead;
                        } else {
                            while (cur.nextedge != null) cur = cur.nextedge;
                            cur.nextedge = new edge();
                            cur = cur.nextedge;
                            cur.node = edges[i][1];
                            cur.weight = edges[i][2];
                            points[edges[i][0]].out++;
                            points[edges[i][1]].in++;
                            inmap[edges[i][1]][edges[i][0]] = 1;
                        }
                    }
                }
            }
        }
    }

成功截图:

 

 

 

(2) 图的遍历:完成有向图和无向图的遍历(深度和广度优先遍历)(4分)

紧接上面的,在mymap类中实现两种便利

代码:

void bfs() {//广度优先遍历
        if (points == null || points.length == 0) return;
        Queue<point> queue = new LinkedList<point>();
        boolean[] visited = new boolean[points.length];
        for (int i = 0; i < visited.length; i++) {
            visited[i] = false;
        }
        queue.offer(points[0]);
        visited[0] = true;
        System.out.print(points[0].pname + " ");
        while (!queue.isEmpty()) {
            point v = queue.remove();
            edge e = v.edgehead;
            while (e != null && visited[e.node] == false) {
                queue.offer(points[e.node]);
                visited[e.node] = true;
                System.out.print(e.node + " ");
                e = e.nextedge;
            }
        }
    }

    void dfs() {//深度优先遍历
        if (points == null || points.length == 0) return;
        boolean[] visited = new boolean[points.length];
        for (int i = 0; i < visited.length; i++) {
            visited[i] = false;
        }
        Stack<point> stack = new Stack<point>();
        stack.push(points[0]);
        visited[0] = true;
        while (!stack.isEmpty()) {
            point v = stack.pop();
            visited[v.pname] = true;
            System.out.print(v.pname + " ");
            edge e = v.edgehead;
            while (e != null && visited[e.node] != true) {
                stack.push(points[e.node]);
                e = e.nextedge;
            }
        }
    }

成功截图:

 

 

 

(3) 完成有向图的拓扑排序,并输出拓扑排序序列或者输出该图存在环(3分)

代码:

void toposort() {//拓扑排序
        Stack s = new Stack();

        for (int l = 0; l < points.length; l++) {
            if (points[l].in == 0) {
                s.push(points[l].pname);
                points[l].in = -1;
            }
        }
        while (!s.isEmpty()) {
            int m = (int) s.peek();
            System.out.print(s.peek() + " ");
            s.pop();
            for (int f = 0; f < points.length; f++) {
                if (inmap[f][m] == 1) {
                    points[f].in--;
                }
            }
            for (int k = 0; k < points.length; k++) {
                if (points[k].in == 0) {
                    s.push(points[k].pname);
                    points[k].in = -1;
                }
            }
        }
    }

成功截图:

 

 

 

(4) 完成无向图的最小生成树Prim算法

    public void prim(int s) {
        int[] distance=new int[points.length];  //记录到起点的距离
        //初始化到起点的距离
        for(int i=0;i<points.length;i++) {
            distance[i]=getWeight(s, i);  //起点到顶点i的权值
        }
        int[] prims=new int[points.length];  //记录访问的顶点序号
        int index=0;  //prims[]的索引
        prims[index++]=s;  //第一个访问的是起点s
        
        //遍历所有顶点,并更新到起点的距离
        for(int i=0;i<points.length;i++) {
            if(i==s) {
                continue;
            }
            int min=INF;
            int k=-1;
            for(int j=0;j<points.length;j++) {
                if(distance[j]!=0 && distance[j]<min) {
                    min=distance[j];
                    k=j;
                }
            }          
            prims[index++]=k; 
            distance[k]=0; 
            for(int j=0;j<points.length;j++) {
                if(getWeight(k, j)==INF) {
                    continue;
                }
                int tmp=distance[k]+getWeight(k, j);               
                if(distance[j]!=0 && distance[j]>tmp) {
                    distance[j]=tmp;
               }
            }            
        }
        
        //打印最小生成树
        System.out.printf("prim(%c)\n",vertex[s].data);
        for(int i=0;i<vertex.length-1;i++) {
            System.out.print(vertex[prims[i]].data+"-->");
        }
        System.out.print(vertex[prims[vertex.length-1]].data);
        int sum=0; //最小权值和
        for(int i=1;i<vertex.length;i++) {
            int min=INF;
            for(int j=0;j<i;j++) {
                if(getWeight(prims[i], prims[j])<min) {
                    min=getWeight(prims[i], prims[j]);
                }
            }
            sum+=min;
        }
        System.out.print("最小权值和为:"+sum);
        System.out.println();
    }
    
    //判断v是不是u的邻接点
    public boolean getAdjVertex(int u,int v) {
        Node tmp=vertex[u].firstEdge;
        while(tmp!=null) {
            if(tmp.index==v) {
                return true;
            }
            tmp=tmp.nextNode;
        }
        return false;
    }

 

 

 

(5) 完成有向图的单源最短路径求解(迪杰斯特拉算法)

        
public void dijkstra(int s) {
int[] path=new int[points.length]; //记录到起点经过的顶点路径 int[] distance=new int[points.length]; //记录到起点的距离 boolean[] visited=new boolean[points.length]; //标记是否访问过 //初始化到起点的距离 for(int i=0;i<points.length;i++) { distance[i]=getWeight(s, i); if(i!=s && distance[i]<INF) { path[i]=s; }else { path[i]=-1; } } visited[s]=true; //起点已经访问过了 //遍历所有顶点,并更新到起点的距离 for(int i=0;i<points.length;i++) { if(i==s) { continue; } int min=INF; int k=-1; //找到距离起点距离最短的顶点 //distance[j]=0,表示已经访问过了 for(int j=0;j<points.length;j++) { if(visited[j]==false && distance[j]<min) { min=distance[j]; k=j; } } visited[k]=true; //第k个顶点已经访问过了 //更新顶点k的邻接点到起点的最小距离 for(int j=0;j<points.length;j++) { //如果不是k的邻接点 if(getWeight(k, j)==INF) { continue; } int tmp=distance[k]+getWeight(k, j); //如果是未被访问过的邻接点,则更新其到起点的距离 if(visited[j]==false && distance[j]>tmp) { distance[j]=tmp; path[j]=k; } } } for(int i=0;i<points.length;i++) { System.out.print(path[i]+" "); int tmp=i; while(tmp!=-1) { System.out.print(vertex[tmp].data+"<--"); tmp=path[tmp]; } System.out.print(" 最小权值为:"+distance[i]); System.out.println(); } private int getWeight(int start, int end) { if (start==end) return 0; edge edge1 = points[start].node.edgehead; while (edge1!=null) { if (end==edge1.node) return edge1.weight; edge1 = edge1.nextedge; } return INF; }

 

 

##思考、感悟和其他

课程也临近尾声了,也是最后一个实验了,时间很快,学习java的一路上也是磕磕绊绊,但也充满了乐趣。

很开心是王老师叫我们java和数据结构,在学习的路上带来了好多快乐,幽默风趣的课堂让本来不简单的java一点都不枯燥。

课程结束,缘分还远远不止,以后也会经常叨扰超人的哈哈哈哈。

撒花!