黑暗中奔跑,看不清颜色,胜负未定,让你半子又何妨?------ ydfy的csdn

ydfy

20182319 2019-2020-1 《数据结构与面向对象程序设计》实验九报告


课程:《程序设计与数据结构》
班级: 1823
姓名: 彭淼迪
学号:20182319
实验教师:王志强
实验日期:2019年12月7日
必修/选修: 必修

1.实验内容

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

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

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

  • (4) 完成无向图的最小生成树(Prim算法或Kruscal算法均可),并输出(3分)

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

2. 实验过程及结果

  其实大部分都已经写过了,对于这部分我们已经实现过的,我们只需要把它一下就好了,所以我们这一次的任务在某一部分会比较轻松,当然,也是只有某一部分。还是有一部分比较难的,比如说我们的最小生成树的算法,虽然以前用手算过,但毕竟是人用全局的想法在做,落实到代码上可就没有那么简单了。

  • 首先,是找出我们已经做过的部分,java的一大优势就在于它的调用使一段代码的利用率高,可以被我们多次利用,我们自然也不能放过这个机会。我们可以发现我们是已经实现过(1)(2)(3)(5),但是我们要怎么用它们呢?有一个办法是直接继承,另一个方法是在我们这个新方法里开原来的类,因为继承是一种比较官方的方法,很多人都会这么用,所以我选择了开新的类。其中那个Boolean型表示的是它是有向还是无向的。ph表示的是原来的图,tuo表示的是原来拓扑排序。可以看到我在后面是直接用了它们的东西的。
private photo1 ph=new photo1();
    private tuopu tuo=new tuopu();
    private boolean f;
    public photo2(boolean f){
            this.f=f;
    }
    public void insertpoint(int a){
        ph.insertpoint(a);
        tuo.insertpoint(a);
    }
    public void deletepoint(int a){
        ph.deletepoint(a);
        tuo.deletepoint(a);
    }
    public void insertline(int a,int b,int c){
        ph.insertline(a,b,c);
        tuo.insertline(a,b,c);
        if(f){
            ph.insertline(b,a,c);
            tuo.insertline(b,a,c);
        }
    }
    public void insertline(int a,int b){
        ph.insertline(a,b);
        tuo.insertline(a,b);
        if(f){
            ph.insertline(b,a);
            tuo.insertline(b,a);
        }
    }
  • 然后,我们需要实现的就只有一个最小生成树了,我们可以直接把它加在我们这个新类里,但是我们这个新类的局限性还是挺大的,毕竟它牵扯到的东西太多了,所以我的想法是把这个方法分给两个原型,因为拓扑里不太用得着,而且这个方法要用到许多图里的参数,所以我是分配给了图。
  • 按照老师上课说过的方法,我们可以使用prim或Kruscal,在这里,我选用的是prim算法,就是每次都从已有的点有找距离这些点中任意一点最近的一个点,然后把这加入到已有点列。依次往复,直到结束。
 public int[][] smallest(){
        int[][] result=new int[200][2];
        int[] dp1=new int[200],dp2=new int[200];
        int min=0;
        for(int i=0;i<200;i++){
            if(p1[i]){min=i;break;}
        }
        for(int i=0;i<200;i++){
            dp1[i]=999999;
            dp2[i]=999999;
            result[i][0]=999999;
            result[i][1]=999999;
        }
        dp1[min]=0;
        result[min][1]=min;
        result[min][0]=0;
        int count1=1;
        while(count1!=count){
            int a=199,b=999999,c=999999;
            for(int i=0;i<200;i++){
                if(panduan1(i,dp1)){
                    for(int j=0;j<200;j++){
                        if(!panduan1(j,dp1)){
                            for(int k=0;k<200;k++){
                                if(panduan1(k,dp1)&&tu[k][j]!=0&&tu[k][j]<c){
                                    a=j;
                                    b=k;
                                    c=tu[k][j];
                                }
                            }
                        }
                    }
                }
            }
            dp1[a]=c;
            result[a][0]=c;
            result[a][1]=b;
            count1++;
        }
        return result;
    }
  • 中间那一段阶梯状的确有点长,不太好看,不过它却是我们刚刚说到的那个方法实现所在。然后也是一沿用了我一贯的风格,把999999当无穷大。
  • 当然,这么好玩的程序自然也不能少了一点人性化的输入输出是不是,于是出于人性化的考虑,我也特地为客户增加了许多可以选择的方向,让他们可以自己选择进行什么操作,什么时候停止。让人用得舒适放心。
System.out.println("请问你是想要输入有向图还是无向图?(输入1为无向图,输入2为有向图)");
            int n=scan.nextInt();
            photo2 ph =new photo2(n==1);
            System.out.println("你想输入几个点?");
            int t=scan.nextInt();
            System.out.println("你可以开始输入了:");
            for(int i=0;i<t;i++){
                int pmd=scan.nextInt();
                ph.insertpoint(pmd);
            }
            System.out.println("你想输入几条边呢?");
            t=scan.nextInt();
            System.out.println("它是有权的吗?(输入1为无权图,输入2为有权图)");
            int pmd0=scan.nextInt();
            System.out.println("你可以输入了:");
            if(pmd0==1){
                System.out.println("输入的格式为“出点 入点”");
                for(int i=0;i<t;i++){
                    int pmd1=scan.nextInt(),pmd2=scan.nextInt();
                    ph.insertline(pmd1,pmd2);
                }
            }
            else{
                System.out.println("输入的格式为“出点 入点 权”");
                for(int i=0;i<t;i++){
                    int pmd1=scan.nextInt(),pmd2=scan.nextInt(),pmd3=scan.nextInt();
                    ph.insertline(pmd1,pmd2,pmd3);
                }
            }
            int x;
            do{
                System.out.println("请输入你想进行的操作:\n1.表示广度优先遍历\n2.表示深度优先遍历\n3.表示拓扑排序\n4.表示生成最小生成树\n5.表示求两点最近距离\n6.不要这个图了");
                x=scan.nextInt();
                switch(x){
                    case 1:
                        ph.bfs();
                        break;
                    case 2:
                        ph.dfs();
                        break;
                    case 3:
                        System.out.println(ph.tuopu());
                        break;
                    case 4:
                        int pmd[][]=ph.smallest();
                        System.out.print("         陈列点:");
                        for(int j=0;j<200;j++){
                            if(pmd[j][0]!=999999) System.out.printf("%8d  ",j);
                        }
                        System.out.println("");
                        System.out.print("       上一个点:");
                        for(int j=0;j<200;j++){
                            if(pmd[j][0]!=999999) System.out.printf("%8d  ",pmd[j][1]);
                        }
                        System.out.println("");
                        System.out.print("与上一个点的距离:");
                        for(int j=0;j<200;j++){
                            if(pmd[j][0]!=999999) System.out.printf("%8d  ",pmd[j][0]);
                        }
                        System.out.println("");
                        break;
                    case 5:
                        int pmd1=scan.nextInt(),pmd2=scan.nextInt();
                        System.out.println(ph.shorest(pmd1,pmd2));
                        break;
                }
            }while(x!=6);

运行结果

在这里插入图片描述

3. 实验过程中遇到的问题和解决过程

  • 问题1:除了(4)我们都是可以用原来的东西,但我们需要新加入一个最小生成树的方法,我们应该怎么办呢?
  • 问题1解决方案:在前面的介绍中,我们已经提到过我们可以使用继承和引用的方法,但其实我们还没有考虑到这个新方法我们应该怎么把它融入进去,我觉得有三个方法:一、直接加在我们的新类里,让它成为新类的一部分,这个方法确实可以满足眼下的要求,但仅此而已;二、我们可以开一个专门的类,我们用这个专门的类来实现,这个方法有两点不妥,其一,为了一个单独的功能就开一个新的类,这无疑会加重以后我们使用时的负担,本来新建一个类是为了方便,结果反而会更不方便,那要它有什么用。其二,最小生成树有许多都要依靠我们的图,我们新建的这个类最后还是要依靠我们的图。所以我选择了方法三:我们把这个方法加在我们的图的类里,因为我们本来就要调用图,我们也没有增加多少事,反而让我们的图这个类更加完善,而且我们也不用另外再开一个图来制造麻烦,可谓一举两得。
posted on 2019-12-08 21:35  ydfy  阅读(165)  评论(0编辑  收藏  举报