lab1回顾 (4) ——P3——Social Network&实验感受

Social Network即为社交网络

任务描述

该任务需要模拟一个简单的人际关系网,抽象来看就是一个无向图。具体任务有:添加点、添加边、求最短路径。健壮性主要围绕名字这部分来编写代码,即每个点对应一个唯一的名字,检查是否输入重名或不输入名字,以及检查是否重复添加边。

其实就是一个无向图,这里用了弗洛伊德算法。

健壮性

在这里有一些健壮性判断的条件:
1.初始化Person时未输入姓名,则给予一个缺省值“NONE”
2.重复加入两次点
3.在未加入点时加入边
4.重复加入两次边
5.在未加入点时计算两点距离

    private boolean Robustness(int left_index, int right_index, Person left, Person right) { //健壮性判断
        if (left_index == -1) {
            System.out.println("The name " + left.getName() + " you entered does not exist in the graph");
            return true;    //若找不到left这个人
        }
        if (right_index == -1) {
            System.out.println("The name " + right.getName() + " you entered does not exist in the graph");
            return true;    //若找不到right这个人
        }
        return left_index == right_index;   //若输入的两人是同一人则返回true
    }

设计/实现FriendshipGraph类

该类需要建立一个图结构所需的关系矩阵、距离矩阵,以及一个名字构成的列表,设计各种方法:添加点、添加边、求最短路径。

各开辟一个100×100的空间作为矩阵来存储,其中vertex数组用来存放关系(即两人之间是否有连线),distance数组用来存放两人之间的距离,Persons数组用来存放名字,number用来记录人数。

private final boolean[][] vertex = new boolean[100][100];
private final int[][] distance = new int[100][100];
private int number = 0; //记录人数
private final String[] persons = new String[100];

实现增加点的函数,其实现原理是:
每当调用一次addVertex函数时,先在人名列表中搜索此人名,若已存在则说明该点重复添加,抛出异常。
否则在人名列表中添加此人名,并将人数加1。

    public boolean addVertex(Person person) {
        for (String p : persons)
            if (Objects.equals(person.getName(), p))
                throw new RuntimeException("Each person has a unique name "); //存在相同名字则抛出异常
        if (Objects.equals(person.getName(), "NONE")) {
            System.out.println("The name you entered is not a proper name");
            return false;
        }
        persons[number++] = person.getName();
        return true;
    }

实现增加边的函数,其实现原理是:
将参数left和 right的合法性进行检查,优先检查这两点是否已在图中存在,否则返回false。其次,若这条边已添加过,也输出"This edge already exists"的错误信息。
若均符合健壮性要求,则更新关系矩阵的值为true,距离矩阵的值为1。

    public boolean addEdge(Person left, Person right) {//在关系图中加入边
        int left_index = find_index(left);//找到left对应的下标
        int right_index = find_index(right);//找到right对应的下标
        if (Robustness(left_index, right_index, left, right)) return false; //健壮性判断
        if (vertex[left_index][right_index]) {
            System.out.println("This edge already exists");
            return false;   //这条边已存在
        }
        vertex[left_index][right_index] = true;
        distance[left_index][right_index] = 1;
        return true;
    }

计算两点间最短路径的函数,其实现原理是:
调用判断健壮性的函数检查这两点是否已在图中存在。接下来调用Floyd算法:

    private void Floyd() {
        for (int i = 0; i < number; i++) {
            for (int j = 0; j < number; j++) {
                for (int k = 0; k < number; k++) {
                    if (distance[i][k] + distance[k][j] < distance[i][j]) {
                        distance[i][j] = distance[i][k] + distance[k][j];
                    }
                }
            }
        }
    }
    public int getDistance(Person left, Person right) {
        int left_index = find_index(left);
        int right_index = find_index(right);
        if (Robustness(left_index, right_index, left, right)) return 0; //健壮性判断
        Floyd();    //弗洛伊德算法
        int dis = distance[left_index][right_index];
        return dis < 100 ? dis : -1;
    }

3.3.2 设计/实现Person类

为Person类设计了get和set方法。
其中get方法可以用来获取数据,set方法用来修改数据。
健壮性检查:若提供的参数为空,则给予一个缺失值“NONE”。

public class Person {
    private String name;
    /*
     * 无参数的构造函数
     * 若无参数,则缺省值为“NONE”
     */
    public Person() {
        this.name = "NONE";
    }
    public Person(String name) {
        if (name.length() == 0)
            this.name = "NONE";
        else this.name = name;
    }
    //方法getname,获取当前对象的name值
    public String getName() {
        return this.name;
    }
    //方法setname,设置当前对象的name值
    public boolean setName(String name) {
        if (name.length() == 0){
            System.out.println("You didn't enter any characters!");
            return false;
        }
        this.name = name;
        return true;
    }
}

Junit测试

第一部分:测试person类

即测试getName和setName方法,着重测试输入参数为空的情况。

    @Test
    public void Person_Test() {
        Person rachel = new Person("Rachel");
        Person ross = new Person("Ross");
        Person ben = new Person("Ben");
        Person kramer = new Person("Kramer");
        Person NONE = new Person();
        //控制台输出了"You didn't enter any characters!"的信息
        //并给予NONE一个缺省值"NONE"
        //--------------以下是测试getname方法--------------
        assertEquals("Rachel", rachel.getName());
        assertEquals("Ross", ross.getName());
        assertEquals("Ben", ben.getName());
        assertEquals("Kramer", kramer.getName());
        //--------------以下是测试setname方法--------------
        assertFalse(ross.setName(""));
        assertTrue(ben.setName("TestName"));
        assertEquals("TestName", ben.getName());
    }

第二部分:测试friendshipGraph类

测试了三个方法:addVertex、addEdge、getDistance。

包括基本功能测试、重复输入相同对象姓名的情况、人名未输入便加入图中的情况、未被加入图中就尝试加边的情况、重复加边的情况、getDistance时但图中不存在该节点的情况。

①基本功能测试,即为与main()函数相似的常规测试,检查是否正确加入点和边,是否返回正确的最短距离。

    @Test
    public void FriendshipGraph_Test() {
        FriendshipGraph graph = new FriendshipGraph();
        Person rachel = new Person("Rachel");
        Person ross = new Person("Ross");
        Person ben = new Person("Ben");
        Person kramer = new Person("Kramer");
        graph.addVertex(rachel);
        graph.addVertex(ross);
        graph.addVertex(ben);
        graph.addVertex(kramer);
        graph.addEdge(rachel, ross);
        graph.addEdge(ross, rachel);
        graph.addEdge(ross, ben);
        graph.addEdge(ben, ross);
        assertEquals(1, graph.getDistance(rachel, ross)); //Should output 1
        assertEquals(2, graph.getDistance(rachel, ben)); //Should output 2
        assertEquals(0, graph.getDistance(rachel, rachel)); //Should output 0
        assertEquals(-1, graph.getDistance(rachel, kramer)); //Should output -1
    }

②重名元素异常测试,再次加入相同人名时是否正确抛出异常(RuntimeException)

    @Test(expected = RuntimeException.class)
    public void Person_Same_Name_Test() {
        FriendshipGraph graph = new FriendshipGraph();
        Person ben1 = new Person("Ben");
        Person ben2 = new Person("Ben");
        assertTrue(graph.addVertex(ben1));
        graph.addVertex(ben2);
    }

③检查在getDistance时输入两个相同对象姓名的情况

    @Test
    public void addVertex_Same_Name_Test() {
        FriendshipGraph graph = new FriendshipGraph();
        Person ben = new Person("Ben");
        graph.addVertex(ben);
        assertEquals(0, (graph.getDistance(ben, ben)));//Should output 0
    }

④其他各种情况的测试
太多了,就不一一列举了。

至此,P3就正式完成了

学习Java感受

这门语言给我最大的感觉就是很博大,有种深不见底的感觉。在我学习了第一门语言C后,我又接触了诸如C++,Python,JavaScript这些语言感觉并不复杂,直到我遇见了Java,在深入学习的过程中许多崭新的概念一点一点地冲击着我的心灵——公有,私有,包,类,接口,方法,实例化,静态,动态,代码块,继承,接口,抽象类,重载,封装,多态,继承……这些都是我闻所未闻的,就好比进入了一扇新世界的大门。概念太多导致我经常将它们混淆而难以区分。感觉Java给我们提供了各种各样的用法,当然也让我有点选择困难症了,比如私有和公有的区别、匿名类和实例化的区别……让我有时候因为不懂它们的区别而难以选择合适的功能。而且Java的编译机制也让我觉得很独特,它会把一个项目文件夹下的所有.java文件全部编译为.class文件——而在C/C++中一个项目仅允许有一个.c/.cpp文件且只会产生一个exe文件。

其实对于Java的初学者来说可以将它的一些新概念类比为C/C++中类似的概念——例如类可看作是对结构体功能的拓展,扩展了方法、静态变量等;包可以类比头文件,虽然包中还有子包的概念……

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值