目录
前言
完成了Poetic Walks和Social Network两个任务。
一、Poetic Walks
接口的规约和实现。
1.Test Graph <L>
(1)Graph接口的测试
Graph仅是一个接口,想要测试Graph,需在接口的实现类ConcreteEdgesGraph,ConcreteVerticesGraph中对方法进行具体实现后才能出现测试结果。如用ConcreteEdgesGraph作为Graph接口的具体实现类,只需要修改empty()。
/**
* Create an empty graph.
*
* @param <L> type of vertex labels in the graph, must be immutable
* @return a new empty weighted directed graph
*/
public static <L> Graph<L> empty() {
return new ConcreteEdgesGraph<L>(new HashSet<L>(), new ArrayList<Edge<L>>());
}
测试add方法
@Test
public void testadd() {
Graph<String> graph=emptyInstance();
assertEquals(true,graph.add("gaorui"));
assertEquals(true,graph.vertices().contains("gaorui"));
assertEquals(false,graph.add("gaorui"));
assertEquals(true,graph.add("curry"));
assertEquals(true,graph.vertices().contains("curry"));
assertEquals(false,graph.add("curry"));
assertEquals(true,graph.add("wiggins"));
assertEquals(true,graph.vertices().contains("wiggins"));
assertEquals(false,graph.add("wiggins"));
}
测试set方法
@Test
public void testset() {
Graph<String> graph=emptyInstance();
graph.add("gaorui");
graph.add("curry");
assertEquals(-1,graph.set("gaorui", "curry", -30));
assertEquals(0,graph.set("gaorui", "curry", 30));
assertEquals(0,graph.set("wiggins", "green", 23));
assertEquals(true,graph.vertices().contains("wiggins"));
assertEquals(true,graph.vertices().contains("green"));
assertEquals(0,graph.set("wiggins", "thompson", 11));
assertEquals(true,graph.vertices().contains("thompson"));
assertEquals(0,graph.set("lee", "looney", 0));
assertEquals(0,graph.set("poole", "wiggins", 3));
assertEquals(true,graph.vertices().contains("poole"));
assertEquals(30,graph.set("gaorui", "curry", 20));
assertEquals(20,graph.set("gaorui", "curry", 0));
assertEquals(0,graph.set("gaorui", "curry", 20));
}
测试remove方法
@Test
public void testremove() {
Graph<String> graph=emptyInstance();
graph.add("gaorui");
graph.add("curry");
graph.set("gaorui", "thompson", 11);
graph.set("gaorui", "green", 23);
graph.set("curry", "gaorui", 30);
assertEquals(true,graph.remove("gaorui"));
assertEquals(false,graph.vertices().contains("gaorui"));
assertEquals(false,graph.sources("thompson").containsKey("gaorui"));
assertEquals(false,graph.sources("green").containsKey("gaorui"));
assertEquals(false,graph.targets("curry").containsKey("gaorui"));
assertEquals(true,graph.remove("curry"));
assertEquals(false,graph.vertices().contains("curry"));
assertEquals(false,graph.remove("gaorui"));
assertEquals(false,graph.remove("curry"));
}
测试vertices方法
@Test
public void testvertices() {
Graph<String> graph=emptyInstance();
Set<String> test=new HashSet<>();
assertEquals(graph.vertices(), test);
graph.add("gaorui");
test.add("gaorui");
assertEquals(graph.vertices(), test);
graph.add("curry");
test.add("curry");
assertEquals(graph.vertices(), test);
graph.add("wiggins");
test.add("wiggins");
assertEquals(graph.vertices(), test);
graph.remove("gaorui");
test.remove("gaorui");
assertEquals(graph.vertices(), test);
}
测试sources方法
@Test
public void testsources() {
Graph<String> graph=emptyInstance();
Map<String, Integer> test = new HashMap<String,Integer>();
graph.set("curry","gaorui", 30);
test.put("curry", 30);
assertEquals(graph.sources("gaorui"),test);
graph.set("wiggins","gaorui", 22);
test.put("wiggins", 22);
assertEquals(graph.sources("gaorui"),test);
graph.set("curry", "gaorui", 0);
test.remove("curry");
assertEquals(graph.sources("gaorui"),test);
graph.set("thompson", "gaorui", 11);
test.put("thompson", 11);
assertEquals(graph.sources("gaorui"),test);
graph.set("wiggins", "gaorui", 0);
test.remove("wiggins");
assertEquals(graph.sources("gaorui"),test);
}
测试targets方法
@Test
public void testtargets() {
Graph<String> graph=emptyInstance();
Map<String, Integer> test = new HashMap<String,Integer>();
graph.set("gaorui", "curry", 30);
test.put("curry", 30);
assertEquals(graph.targets("gaorui"),test);
graph.set("gaorui", "wiggins", 22);
test.put("wiggins", 22);
assertEquals(graph.targets("gaorui"),test);
graph.set("gaorui", "curry", 0);
test.remove("curry");
assertEquals(graph.targets("gaorui"),test);
graph.set("gaorui", "thompson", 11);
test.put("thompson", 11);
assertEquals(graph.targets("gaorui"),test);
graph.set("gaorui", "wiggins", 0);
test.remove("wiggins");
assertEquals(graph.targets("gaorui"),test);
}
对于实现类的测试只需要继承接口的测试,再分别加入Edge和Vertex的测试和toString的测试。
(2)ConcreteEdgesGraph的测试
@Test
public void testConcreteEdgeGraphtoString1() {
ConcreteEdgesGraph<String> emptyGraph=new ConcreteEdgesGraph<String>(new HashSet<String>(), new ArrayList<Edge<String>>());
String a="a";
String b="b";
emptyGraph.add(a);
emptyGraph.add(b);
String ans="Points: a, b\n";
ans+="edges: \n";
assertEquals(true,emptyGraph.toString().equals(ans));
}
@Test
public void testConcreteEdgeGraphtoString2() {
ConcreteEdgesGraph<String> emptyGraph=new ConcreteEdgesGraph<String>(new HashSet<String>(), new ArrayList<Edge<String>>());
String a="a";
String b="b";
emptyGraph.set(a,b,10);
String ans="Points: a, b\n";
ans+="edges: \n";
ans+="a b 10\n";
assertEquals(true,emptyGraph.toString().equals(ans));
}
@Test
public void testConcreteEdgeGraphtoString3() {
ConcreteEdgesGraph<String> emptyGraph=new ConcreteEdgesGraph<String>(new HashSet<String>(), new ArrayList<Edge<String>>());
String ans="Points: \n";
ans+="edges: \n";
assertEquals(true,emptyGraph.toString().equals(ans));
}
@Test
public void testtoString() {
Edge<String> edge=new Edge<String>("a","b",10);
String ans="a b 10\n";
assertEquals(true,edge.toString().equals(ans));
}
(3)ConcreteVerticesGraph的测试
@Test
public void testConcreteVerticesGraphtoString1() {
ConcreteVerticesGraph<String> emptyGraph=new ConcreteVerticesGraph<String>(new ArrayList<Vertex<String>>());
String a="a";
String b="b";
emptyGraph.add(a);
emptyGraph.add(b);
String ans="a, b\n";
assertEquals(true,emptyGraph.toString().equals(ans));
}
@Test
public void testConcreteVerticesGraphtoString2() {
ConcreteVerticesGraph<String> emptyGraph=new ConcreteVerticesGraph<String>(new ArrayList<Vertex<String>>());
String ans="";
assertEquals(true,emptyGraph.toString().equals(ans));
}
@Test
public void testtoString() {
Vertex<String> points=new Vertex<String>("a","b",10);
points.addedge("c",20);
String ans=points.getsource()+":\n";
ans+="b 10\n";
ans+="c 20\n";
assertEquals(true,points.toString().equals(ans));
}
2.Implement Graph <L>
使用Graph接口实现ConcreteEdgeGraph类和ConcreteVerticesGraph类。
(1)Edge类
首先定义一个Edge类。
field:source:边的起点;target:边的终点;weight:边的权值。
private final L source;
private final L target;
private final int weight;
构造函数
public Edge(L source, L target, int weight) {
this.source=source;
this.target=target;
this.weight=weight;
checkRep();
}
checkRep
private void checkRep() {
assert weight>0;
}
三个get方法分别可以返回边的起点,边的终点,边的权值。
public L getsource() {
return source;
}
public L gettarget() {
return target;
}
public int getweight() {
return weight;
}
重写toString方法:将边转换为一个字符串,形式为“source target weight\n”。
@Override
public String toString() {
checkRep();
return source+" "+target+" "+weight+"\n";
}
(2)ConcreteEdgeGraph类的实现
然后利用Edge类实现ConcreteEdgeGraph类。
Abstraction function
AF(顶点,边)=图中的所有点,图中的所有单向边
Representation invariant
vertices是所有点的集合。它不包含相同的点。每个边的起点和终点应该在vertices集合中。edges是所有边的列表。所有边的权值都应该是正的。所有的边都是单向的。它应该有起点和终点。所有的边都应该有一个不同的起点或终点。
Safety from rep exposure
所有field都是私有的。vertices是一个可变Set,因此ConcreteEdgesGraph()创建防御性副本以避免与客户端共享代表的Set对象。edges是一个可变的List,因此ConcreteEdgesGraph()会生成防御性副本避免与客户端共享List对象。
checkRep
private void checkRep() {
int size=edges.size(),i,j;
for(i=0;i<size;++i) {
assert vertices.contains(edges.get(i).getsource());
assert vertices.contains(edges.get(i).gettarget());
assert edges.get(i).getweight()>0;
for(j=i+1;j<size;++j)
if(i!=j) {
L source1=edges.get(i).getsource();
L source2=edges.get(j).getsource();
L target1=edges.get(i).gettarget();
L target2=edges.get(j).gettarget();
assert (!source1.equals(source2) || !target1.equals(target2));
}
}
}
add
判断vertices中是否包含要加入的点,如果包含则返回false,如果不包含则将该点加入并返回true。
@Override public boolean add(L vertex) {
if(vertices.contains(vertex)){
return false;
}
else {
vertices.add(vertex);
return true;
}
}
set
首先判断weight是否小于0。然后通过遍历判断要加入的边是否存在,如果存在,记录当前的nowweight,并判断输入的weight是否为0,如果为0就删除这条边,如果不为了就更新weight,最后返回记录的nowweight。如果不存在这条边,同样判断weight是否为0,如果不为0就加入这条边,并且将未加入的点加入vertices中,并且返回0。
@Override public int set(L source, L target, int weight) {
if(weight<0) {
System.out.println("The weight of the edge should be positive");
return -1;
}
else {
for(Edge<L> now:edges)
{
if(now.getsource().equals(source)&&now.gettarget().equals(target)) {
int nowweight=now.getweight();
edges.remove(now);
if(weight!=0){
Edge<L> newedge=new Edge<L>(source,target,weight);
vertices.add(source);
vertices.add(target);
edges.add(newedge);
}
return nowweight;
}
}
if(weight!=0) {
Edge<L> newedge=new Edge<L>(source,target,weight);
vertices.add(source);
vertices.add(target);
edges.add(newedge);
}
return 0;
}
}
remove
遍历vertices如果该顶点不存在则返回false,如果该顶点存在则删除该顶点,并将所有相关边删除,然后返回ture。
@Override public boolean remove(L vertex) {
if(!vertices.contains(vertex)) {
return false;
}
vertices.remove(vertex);
for(Iterator<Edge<L>> it=edges.iterator();it.hasNext();) {
Edge<L> now=it.next();
if(now.getsource().equals(vertex) || now.gettarget().equals(vertex)) {
it.remove();
}
}
return true;
}
vertices
创建一个新的集合,复制vertices集合并返回。
@Override public Set<L> vertices() {
Set<L> copyvertices=new HashSet<>();
copyvertices.addAll(vertices);
return copyvertices;
}
sources
遍历edges,找到所有以输入的点为终点的边,并将其起点和权值加入集合。
@Override public Map<L, Integer> sources(L target) {
checkRep();
Map<L,Integer> sources=new HashMap<L,Integer>();
for(Edge<L> now:edges) {
if(now.gettarget().equals(target)) {
sources.put(now.getsource(), now.getweight());
}
}
return sources;
}
targets
遍历edges,找到所有以输入的点为起点的边,并将其终点和权值加入集合。
@Override public Map<L, Integer> targets(L source) {
checkRep();
Map<L, Integer> targets=new HashMap<L,Integer>();
for(Edge<L> now:edges) {
if(now.getsource().equals(source)) {
targets.put(now.gettarget(),now.getweight());
}
}
return targets;
}
toString
遍历vertices和edges,将其转化为对应字符串。
测试ConcreteEdgesGraph结果如下图。
@Override
public String toString() {
checkRep();
String ans;
ans="Points: ";
int i,num=0,size=vertices.size();
Iterator<L> it=vertices.iterator();
while(it.hasNext()) {
ans+=it.next();
++num;
if(num!=size) ans+=", ";
else ans+="\n";
}
if(vertices.size()==0)
ans+="\n";
ans+="edges: \n";
size=edges.size();
for(i=0;i<size;++i)
ans+=edges.get(i).getsource()+" "+edges.get(i).gettarget()+" "+edges.get(i).getweight()+"\n";
return ans;
}
(3)Verterx类
首先定义一个Vertex类。
field
source:该点的命名;Target:以该点为起点的边的终点和权值构成的集合。
private final L source;
private final Map<L,Integer> Target=new HashMap<>();
构造函数
构造时可以只输入该点的source,也可以输入source、target和weight。
public Vertex(L source) {
this.source=source;
checkRep();
}
public Vertex(L source, L target, Integer weight) {
this.source=source;
Target.put(target, weight);
checkRep();
}
checkRep
private void checkRep() {
for(L now:Target.keySet())
assert Target.get(now)>0;
}
get方法
分别可以返回source和Target。
public L getsource() {
return source;
}
public Map<L,Integer> gettargets(){
Map<L,Integer> newtargets=new HashMap<>();
newtargets.putAll(Target);
return newtargets;
}
addEdge和removeEdge
public void removeedge(L target, Integer weight) {
Target.remove(target);
}
public void addedge(L target, Integer weight) {
Target.put(target, weight);
}
toString
遍历Target,每一个元素输出一条边,将边转换为一个字符串,形式为“source target weight\n”。
如果Target为空,则返回“source:\n”。
@Override
public String toString() {
String ans=source+":\n";
for(L key:Target.keySet())
ans+=key+" "+Target.get(key)+"\n";
return ans;
}
(4)ConcreteVerticesGraph类的实现
然后用Vertex类实现ConcreteVerticesGeraph类。
Abstraction function
AF(vertices) =所有点的列表
Representation invariant
vertices中所有的点应该是不同的。这意味着所有顶点的source应该是不同的。
Safety from rep exposure
所有field都是私有的。vertices是一个可变列表,因此ConcreteVerticesGraph()创建防御性副本,避免与客户端共享代表的List对象。
checkRep
veritces中顶点的source不能重复
private void checkRep() {
int i,j,size=vertices.size();
for(i=0;i<size;++i)
for(j=i+1;j<size;++j)
if(i!=j)
assert !vertices.get(i).getsource().equals(vertices.get(j).getsource());
}
add
判断vertices中是否包含要加入的点,如果包含则返回false,如果不包含则将该点加入并返回true。
@Override public boolean add(L vertex) {
for(Vertex<L> v:vertices) {
if(v.getsource().equals(vertex)) {
return false;
}
}
vertices.add(new Vertex<L>(vertex));
return true;
}
set
判断weight是否小于0。如果target不在vertices中则将其加入。然后遍历vertices,如果source在vertices中就遍历这个点的targets集合判断要加入的边是否存在。如果存在记录nowweight。判断weight是否等于0,如果不等于就更新weight。然后返回nowweight,如果targets集合不存在这个边则将其加入。如果sources不在vertices,则调用构造函数构造一个点并将其加入。
@Override public int set(L source, L target, int weight) {
if(weight<0) {
System.out.println("The weight of the edge should be positive");
return -1;
}
add(target);
for(Vertex<L> v:vertices) {
if(v.getsource().equals(source)) {
if(v.gettargets().containsKey(target)) {
int nowweight=v.gettargets().get(target);
v.removeedge(target,nowweight);
if(weight!=0) {
v.addedge(target, weight);
}
return nowweight;
}
else {
v.addedge(target, weight);
return 0;
}
}
}
Vertex<L> vertex;
if(weight!=0) {
vertex=new Vertex<L>(source,target,weight);
}
else {
vertex=new Vertex<L>(source);
}
vertices.add(vertex);
return 0;
}
remove
遍历vertices集合判断是否存在输入的点。如果不存在则返回false,如果存在则删除该点,并删除所有相关边,然后返回true。
@Override public boolean remove(L vertex) {
int flag=0;
for(Iterator<Vertex<L>> it=vertices.iterator();it.hasNext();) {
Vertex<L> now=it.next();
if(now.getsource().equals(vertex)) {
it.remove();
flag=1;
}
else if(now.gettargets().containsKey(vertex)){
Integer weight=now.gettargets().get(vertex);
now.removeedge(vertex, weight);
flag=1;
}
}
if(flag==1) return true;
else return false;
}
vertices
创建一个新的集合,复制vertices集合并返回。
@Override public Set<L> vertices() {
Set<L> s=new HashSet<>();
for(Vertex<L> v:vertices) {
s.add(v.getsource());
}
return s;
}
sources
创建一个新的集合。遍历vertices集合,如果当前点的targets集合中包含输入的点则将当前点和边的权值加入集合中。
@Override public Map<L, Integer> sources(L target) {
checkRep();
Map<L,Integer> m=new HashMap<>();
for(Vertex<L> v:vertices) {
if(v.gettargets().containsKey(target)) {
m.put(v.getsource(), v.gettargets().get(target));
}
}
return m;
}
targets
创建一个新的集合。遍历vertices集合,如果存在这个点则将其targets集合复制并返回。
@Override public Map<L, Integer> targets(L source) {
checkRep();
Map<L,Integer> m=new HashMap<>();
for(Vertex<L> v:vertices) {
if(v.getsource().equals(source)) {
m.putAll(v.gettargets());
}
}
return m;
}
toString
遍历vertices将点和边转化为字符串。
@Override
public String toString() {
String ans="";
int i,size=vertices.size();
for(i=0;i<size;++i) {
ans+=vertices.get(i).getsource();
if(i!=size-1) ans+=", ";
else ans+="\n";
}
return ans;
}
3.Test GraphPoet
定义一个字符串作为输入。读取文件构造一个GraphPoet。调用其poem方法判断返回值与预期字符串是否相等。
public class GraphPoetTest {
@Test(expected=AssertionError.class)
public void testAssertionsEnabled() {
assert false; // make sure assertions are enabled with VM argument: -ea
}
/*
* Test Graph
*/
// Testing strategy for Graph:
// test the vertices
// test the edges
@Test
public void testVertices() throws IOException {
final GraphPoet graph=new GraphPoet(new File("test/P1/poet/test.txt"));
Set<String> vertices=graph.getvertices();
assertEquals(9,vertices.size());
Set<String> ans=new HashSet<>();
ans.add("I".toLowerCase());
ans.add("love".toLowerCase());
ans.add("you".toLowerCase());
ans.add("guys,".toLowerCase());
ans.add("like".toLowerCase());
ans.add("you.".toLowerCase());
ans.add("too.".toLowerCase());
ans.add("so".toLowerCase());
ans.add("much.".toLowerCase());
Iterator<String> it=vertices.iterator();
while(it.hasNext()) {
assertEquals(true,ans.contains(it.next().toLowerCase()));
}
}
@Test
public void testOneStepEdges() throws IOException {
final GraphPoet graph=new GraphPoet(new File("test/P1/poet/test.txt"));
Set<String> vertices=graph.getvertices();
Graph<String> ans = Graph.empty();
ans.set("I".toLowerCase(),"I".toLowerCase(),2);
ans.set("I".toLowerCase(),"love".toLowerCase(),2);
ans.set("I".toLowerCase(),"like".toLowerCase(),3);
ans.set("love".toLowerCase(),"you".toLowerCase(),2);
ans.set("you".toLowerCase(),"you".toLowerCase(),2);
ans.set("you".toLowerCase(),"guys,".toLowerCase(),1);
ans.set("you".toLowerCase(),"I".toLowerCase(),1);
ans.set("you".toLowerCase(),"so".toLowerCase(),1);
ans.set("you".toLowerCase(),"too.".toLowerCase(),1);
ans.set("like".toLowerCase(),"you.".toLowerCase(),1);
ans.set("like".toLowerCase(),"you".toLowerCase(),2);
ans.set("so".toLowerCase(),"much.".toLowerCase(),1);
ans.set("guys,".toLowerCase(),"I".toLowerCase(),1);
ans.set("too.".toLowerCase(),"I".toLowerCase(),1);
ans.set("much.".toLowerCase(),"I".toLowerCase(),1);
Iterator<String> it=vertices.iterator();
while(it.hasNext()) {
String source=it.next();
Map<String,Integer> targets=graph.targets(source);
Map<String,Integer> sttargets=ans.targets(source);
assertEquals(targets.size(),sttargets.size());
for(String key: targets.keySet()) {
assertEquals(true,sttargets.containsKey(key));
assertEquals(true,sttargets.containsValue(targets.get(key)));
}
}
}
@Test
public void testpoem() throws IOException{
final GraphPoet graph=new GraphPoet(new File("test/P1/poet/test.txt"));
final String input="I you much.";
String ans=graph.poem(input);
assertEquals(ans,"I like you so much.");
}
}
4.Implement GraphPoet
(1)构造函数
按行读取一个文件并按空格分割。每个单词作为一个点,每出现两个相邻的单词,判断当前的图中是否有以这个两个单词为起点和终点的边。如果有则将其权值加一,如果没有则调用set方法将边加入。
public GraphPoet(File corpus) throws IOException {
try(FileReader reader = new FileReader(corpus); BufferedReader br = new BufferedReader(reader)) {
String Myline;
String preString="";
while((Myline=br.readLine())!=null) {
String words[]=Myline.split(" ");
int i,size=words.length;
for(i=0;i<size-1;++i) {
int preweight=graph.set(words[i].toLowerCase(),words[i+1].toLowerCase(),0);
graph.set(words[i].toLowerCase(),words[i+1].toLowerCase(),preweight+1);
}
if(!preString.equals("")) {
int preweight=graph.set(preString.toLowerCase(),words[0].toLowerCase(),0);
graph.set(preString.toLowerCase(),words[0].toLowerCase(),preweight+1);
}
preString=words[size-1];
}
}catch(IOException e){
e.printStackTrace();
}
checkRep();
}
(2)checkRep
private void checkRep() {
Set<String> vertices=new HashSet<>();
Set<String> vertex=graph.vertices();
Iterator<String> it=vertex.iterator();
while(it.hasNext()) {
vertices.add(it.next().toLowerCase());
}
assert vertices.size()==vertex.size();
}
(3)poem
将输入的字符串按空格分割生成一个字符串数组,每个元素对应一个单词。遍历这个数组,获取当前元素和下一位元素,调用gettargets方法获得当前元素的所有边的终点的集合,调用getsources方法获得下一位元素的所有边的起点的集合。遍历这两个集合找到其重复的点,并计算该点与当前元素和下一位元素构成的两条边的权值和最大的点。将其加入当前元素和下一位元素之间。
public String poem(String input) {
String mypoem="";
String words[]=input.split(" ");
int i,size=words.length;
for(i=0;i<size-1;++i) {
String source=words[i];
String target=words[i+1];
if(i!=0)
mypoem+=" ";
mypoem+=source;
Map<String,Integer> tobridge=graph.targets(source.toLowerCase());
Map<String,Integer> bridgeto=graph.sources(target.toLowerCase());
int maxn=0;
String maxbridge="";
for(String key: tobridge.keySet()) {
if(bridgeto.containsKey(key)) {
int now=tobridge.get(key)+bridgeto.get(key);
if(now>maxn) {
maxn=now;
maxbridge=key;
}
}
}
if(maxn!=0)
mypoem+=" "+maxbridge;
if(i==size-2)
mypoem+=" "+target;
}
return mypoem;
}
5.代码覆盖度
二、Social Network
继承P1中ConcreteEdgesGraph<Person>或者ConcreteVerticesGraph<Person>类 实现FriendshipGraph,通过基本操作实现FriendshipGraph中addVertex,addEdge和getDistance三个接口,要求不能修改父类rep。
1.FriendshipGraph类
FriendshipGraph类此处继承ConcreteEdgesGraph类,泛型此处应用Person类。
大部分需要的功能在ConcreteEdgesGraph类中都实现了,只需调用相应方法完成需要实现的方法即可。
addVertex方法和addEddge方法可以通过简单的调用ConcreteEdgesGraph类中的方法实现即可。
public void addVertex(Person person) {
if(!friendgraph.add(person)) {
System.out.println("Duplicate names");
System.exit(0);
}
checkRep();
}
public void addEdge(Person source,Person target) {
friendgraph.set(source, target, 1);
checkRep();
}
getDistance方法可以使用Dijistra算法来完成。
public int getDistance(Person x, Person y) {
Person source=new Person(x.getname());
Person target=new Person(y.getname());
if(source.getname().equals(target.getname()))
return 0;
List<Person> l=new ArrayList<>();
List<Integer> dis=new ArrayList<>();
Set<Person> flag=new HashSet<>();
l.add(source);
dis.add(0);
flag.add(source);
int h=0,t=0;
while(h<=t) {
Person u=l.get(h);
Map<Person,Integer> targets=friendgraph.targets(u);
for(Person key: targets.keySet())
if(!flag.contains(key)) {
++t;
flag.add(key);
l.add(key);
dis.add(dis.get(h)+targets.get(key));
if(key.getname().equals(target.getname()))
return dis.get(t);
}
++h;
}
return -1;
}
2.Person类
public class Person
{
private String name;
public Person(String name) {
this.name=name;
}
public String getname() {
return name;
}
@Override
public boolean equals(Object obj) {
Person p=(Person) obj;
return this.name.equals(p.getname());
}
}
3.客户端main()
public class Main {
public static void main(String[] args) {
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);
System.out.println(graph.getDistance(rachel, ross));
// should print 1
System.out.println(graph.getDistance(rachel, ben));
// should print 2
System.out.println(graph.getDistance(rachel, rachel));
// should print 0
System.out.println(graph.getDistance(rachel, kramer));
// should print -1
}
}
4.测试用例
@Test
void friendshipGraphtest()
{
FriendshipGraph graph = new FriendshipGraph();
Person Curry = new Person("Curry");
Person Green = new Person("Green");
Person Thompson = new Person("Thompson");
Person Wiggins = new Person("Wiggins");
Person Looney = new Person("Looney");
graph.addVertex(Curry);
graph.addVertex(Green);
graph.addVertex(Thompson);
graph.addVertex(Wiggins);
graph.addVertex(Looney);
graph.addEdge(Curry, Green);
graph.addEdge(Wiggins, Curry);
graph.addEdge(Wiggins, Looney);
graph.addEdge(Thompson, Looney);
graph.addEdge(Green,Thompson);
assertEquals(0,graph.getDistance(Curry, Curry));
assertEquals(3,graph.getDistance(Curry, Looney));
assertEquals(-1,graph.getDistance(Green,Wiggins));
assertEquals(3,graph.getDistance(Wiggins, Thompson));
}