软构实验Lab2简述分析

Lab2相比Lab1就考的不是提交啥的了,主要是在考规约,注释,写具有独立性的代码,写测试文件,泛型这些构造软件所需要的要素。我们这届Lab2就两部分,P2与Lab1有重合,而且内容也不多,所以主要说一下P1。

1测试文件

Lab2是让你写一个有向图,需要一个构造的边的类ConcreteEdgesGraph和一个点的类ConcreteVerticesGraph,所以对这两个类分别写测试ConcreteEdgesGraphTest和ConcreteVerticesGraphTest,公共的测试写在GraphInstanceTest中,内两个测试都会调用这个测试,最后选用构造的点类和边类的其中一个,按这个构造出有向图,并进行最后的测试GraphStaticTest。具体每个测试中都要写什么,在Graph.java文件的规约中都已经写好了,按照Graph中给出的函数,一个一个写测试代码就好。

代码比较长,而且每个人测试的重点也不一样,所以就不给出测试代码了。

2.类ConcreteEdgesGraph和类ConcreteVerticesGraph

第二部分是这个实验的核心,拿类ConcreteEdgesGraph来说,java文件中需要自己写的就两部分。第一,填写类ConcreteEdgesGraph,缺少的代码就是Graph中让你写内一堆,要求都在规约里,就按照你写的内个测试文件写对应的功能代码就行。唯独没给规约的就一个ToString函数,就一个输出,写一下就行。第二部分是写类Edge,需要满足独立性,所以对于私人域就要用函数来找。考虑一下要求的是mutable还是inmutable,不可变就复制再用,可变就直接改。对于类ConcreteVerticesGraph也是一样的,就不赘述了。下面是代码:

ConcreteEdgesGraph:

/* Copyright (c) 2015-2016 MIT 6.005 course staff, all rights reserved.
 * Redistribution of original or derived work requires permission of course staff.
 */

package P1.graph;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * An implementation of Graph.
 * 
 * <p>PS2 instructions: you MUST use the provided rep.
 */
public class ConcreteEdgesGraph<L> implements Graph<L> {
    
    private final Set<L> vertices = new HashSet<>();
    private final List<Edge<L>> edges = new ArrayList<>();
    
    // Abstraction function:
    //   TODO
    //a graph with weight direct edges,every edge is begin from source and end to
    //target,source and target must be different vertex
    
    // Representation invariant:
    //   TODO
    //the weight must be positive,from a source to a target is only one edge
    
    // Safety from rep exposure:
    //   TODO
    // all of the fields are private and final,because immutable,so they can't be
    //accessed from outside the class or be given a new value,if you want to use 
    //them ,just do some defensive copying in the return.
    
    // TODO constructor
    public ConcreteEdgesGraph() {
        vertices.clear();
        edges.clear();
        checkRep();
    }
    
    public ConcreteEdgesGraph(final List<L> vertices) {
        this.vertices.addAll(vertices);
        checkRep();
    }
    
    // TODO checkRep
    private void checkRep() {
		for(L vertex : vertices) {
            assert vertex != null;
        }
	}
    
    
    @Override public boolean add(L vertex) {
        if (this.vertices.contains(vertex)) return false;
        vertices.add(vertex);
        return true;
        	
    }
    
    @Override public int set(L source, L target, int weight) {
    	//规约里没说小于0的情况,直接抛异常。
        if(weight < 0) throw new RuntimeException("Error, input a negative number");
        //大于0时,需要先检查在不在边集和点集中,不在就加进去。等于0,不在正好,在还要删掉(实现删掉的代码在下面)。
        if (weight > 0) {
        	add(source);
        	add(target);
        }
        //开始更新边
        Edge<L> tempEdge = new Edge<>(source,target,weight); 
        //如果有一模一样的边,则啥也不改,返回权重
        if(edges.contains(tempEdge)) return tempEdge.getWeight();
        //否则更新边或者删除
        for(Edge<L> temp : edges) {
    		if((temp.getSource().equals(source))&&(temp.getTarget().equals(target))) {
    			if(weight == 0) {//当weight是0时,移除对应边
    				edges.remove(temp);
    				return temp.getWeight();
    			}else {//weight不是0时,修改对应边
        			edges.remove(temp);
        			edges.add(tempEdge);
        			return temp.getWeight();
    			}
    		}
    	}
        //如果不是已有边就新建
        if(weight != 0) edges.add(tempEdge);//weight就直接跳过了
        return 0;
        
    }
    
    @Override public boolean remove(L vertex) {

//    	boolean flag = false;
//    	if(vertices.contains(vertex)) {
//    		for(String temp1 : vertices) {
//    			if(temp1.equals(vertex)) {
//    				vertices.remove(temp1);
//    				flag = true;
//    				break;
//    			}
//    		}
//    		if(flag)
//    		{
//    			for(Edge temp2 : edges) {
//        			if(temp2.getSource().equals(vertex) || temp2.getTarget().equals(vertex)) {
//        				edges.remove(temp2);
//        			}
//        		}
//    		}
//    		
//    	}
//   	return flag;
    	Iterator<L> iterator1 = vertices.iterator();
        boolean flag = false;
        while (iterator1.hasNext()) {
            L string = iterator1.next();
            if (string.equals(vertex)) {
                flag = true;
                iterator1.remove();
                break;
            }
        }
        Iterator<Edge<L>> iterator2 = edges.iterator();
        while (iterator2.hasNext()) {
            Edge<L> edge = iterator2.next();
            if (edge.getSource().equals(vertex) || edge.getTarget().equals(vertex)) {
                iterator2.remove();
            }
        }
        checkRep();
        return flag;
    }
    
    @Override public Set<L> vertices() {
    	return new HashSet<L>(vertices);
    }
    
    @Override public Map<L, Integer> sources(L target) {
    	HashMap<L, Integer> sourceMap = new HashMap<L , Integer>();
        for(Edge<L> temp : edges) {
        	if(temp.getTarget().equals(target)) {
        		sourceMap.put(temp.getSource(),temp.getWeight());
        	}
        }
        return sourceMap;
    }
    
    @Override public Map<L, Integer> targets(L source) {
    	HashMap<L, Integer> targetMap = new HashMap<L, Integer>();
        for(Edge<L> temp : edges) {
        	if(temp.getSource().equals(source)) {
        		targetMap.put(temp.getTarget(),temp.getWeight());
        	}
        }
        return targetMap;
    }
    
    // TODO toString()
    @Override 
    public String toString()
    {
    	System.out.println("vertices:");
    	for(L temp1 : vertices) {
			System.out.print(temp1);
			}
		
    	System.out.println("edges:");
    	for(Edge<L> temp2 : edges) {
			System.out.print(temp2);
			}
    	
    	return "vertice number: " + vertices.size() + " edge number: " + edges.size();
    
    }
}

/**
 * TODO specification
 * Immutable.
 * This class is internal to the rep of ConcreteEdgesGraph.
 * 
 * <p>PS2 instructions: the specification and implementation of this class is
 * up to you.
 */
class Edge<L> {
    
    // TODO fields
    private final L source;
    private final L target;
    private final int weight;
	
    // Abstraction function:
    //   TODO
    //an edge class,have source,target and weight
    
    // Representation invariant:
    //   TODO
    //source and target are different,and they can't be NULL
    //weight must be nonnegative
    
    // Safety from rep exposure:
    //   TODO
    // all of the fields are private and final,because immutable,so they can't be
    //accessed from outside the class or be given a new value,if you want to use 
    //them ,just do some defensive copying in the return.
    
    // TODO constructor
    //建立新边的时候就直接给定起点终点和权重。
    public Edge(L source, L target, int weight)
    {
    	this.source = source;
    	this.target = target;
    	this.weight = weight;
    	checkRep();
    }
	
    // TODO checkRep
    public void checkRep() {
		 assert weight >= 0;
	     assert source != null;
	     assert target != null;
	}
    
    
    // TODO methods
    /**
     * @return the source vertex of the directed edge
     */
    public L getSource() {
    	L tempsource = source;
		return tempsource;
	}
    
    /**
     * @return the target vertex of the directed edge
     */
    public L getTarget() {
    	L temptarget = target;
		return temptarget;
	}
    
    /**
     * @return the weight of the directed edge
     */
    public int getWeight() {
    	int tempweight = weight;
		return tempweight;
	}
    
    
    // TODO toString()
    @Override
	public String toString() {
		return this.source + " -> " + this.target + ": " + this.weight + "\n";
	}
}

ConcreteVerticesGraph:

/* Copyright (c) 2015-2016 MIT 6.005 course staff, all rights reserved.
 * Redistribution of original or derived work requires permission of course staff.
 */
package P1.graph;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import P1.graph.Vertex;

/**
 * An implementation of Graph.
 * 
 * <p>PS2 instructions: you MUST use the provided rep.
 */
public class ConcreteVerticesGraph<L> implements Graph<L> {
    
    private final List<Vertex<L>> vertices = new ArrayList<>();
    
    // Abstraction function:
    //   TODO
    //a graph with weight direct edges,every edge is begin from source and end to
    //target,source and target must be different vertex
    
    // Representation invariant:
    //   TODO
    //the weight must be positive,every vertex must be different
    
    // Safety from rep exposure:
    //   TODO
    // all of the fields are private,and mutable.
    
    // TODO constructor
    public ConcreteVerticesGraph() {
        vertices.clear();
        checkRep();
    }
    
    // TODO checkRep
    private void checkRep(){
        final int size = vertices.size();
        if(!vertices.isEmpty()){
            for(int i = 0; i < size; i++) {
                for(int j = i + 1; j < size; j++){
                    assert !vertices.get(i).equals(vertices.get(j));
                }
            }
        }
    }
    
    @Override public boolean add(L vertex) {
    	//建立vertices对应的Set
    	Set<L> vertexSet = vertices();
    	Vertex<L> tempVertex = new Vertex<L>(vertex);//给vertex新建一个点,如果没有就加进去
    	if(!vertexSet.contains(vertex)){
    		vertices.add(tempVertex);
    		return true;
    		}
    	else return false;
    }
    
    @Override public int set(L source,L target, int weight) {
    	//规约里没说小于0的情况,直接抛异常。
        if(weight < 0) throw new RuntimeException("Error, input a negative number");
        //建立vertices对应的Set
        Set<L> vertexSet = vertices();
        Vertex<L> tempSource = findVertex(source);
        Vertex<L> tempTarget = findVertex(target);
        //等于0,不在正好,如果点不在vertices里就可以直接return了。在的情况需要返回边长,下面再写。
        if(weight == 0) {
        	if(!vertexSet.contains(source)||(!vertexSet.contains(target)))
        		return 0;
        }
        //大于0时,需要先检查在不在边集和点集中,不在就加进去。
        if(weight > 0) {
        	add(source);
        	add(target);
        }
        if(tempSource.getTargetEdges().containsKey(target)) {//如果有边
    		//准备好旧的权重,用于返回
    		int oldWeight = tempSource.getTargetEdges().get(target);
    		//如果weight不等于0,更新值 如果weight等于0,删除该边
    		if(weight != 0) {
    			tempSource.getTargetEdges().remove(target);
    			tempSource.getTargetEdges().put(target,weight);
    			tempTarget.getSourceEdges().remove(source);
    			tempTarget.getSourceEdges().put(source,weight);
    		}else {
    			tempSource.getTargetEdges().remove(target);
    			tempTarget.getSourceEdges().remove(source);
    		}
    		return oldWeight;
    	}else {
    		//如果没边如要是等于0,删除不用做因为没有边,直接返回weight也就是0
    		if(weight != 0) {//weight不等于0,在vertices加入边再返回0,
    			tempSource.getTargetEdges().put(target, weight);
    			tempTarget.getSourceEdges().put(source, weight);
    		}//weight等于0就直接跳过了
    		return 0;
    	}
    }
    
    @Override public boolean remove(L vertex) {
    	//建立vertices对应的Set
        Set<L> vertexSet = vertices();
        boolean flag = false;
        if(vertexSet.contains(vertex)) {
        	Vertex<L> tempVertex = findVertex(vertex);
        	//建立以这个点为起点和重点的set
        	Set<L> sourceEdgeSet = tempVertex.getSourceEdges().keySet();
        	Set<L> targetEdgeSet = tempVertex.getTargetEdges().keySet();
        	//更新所有以目标点为终点的点,在他们的getTargetEdges()集合中去除目标点
        	for(L temp1 : sourceEdgeSet) {
    	 		Vertex<L> temp1vertex = findVertex(temp1);
    	 		temp1vertex.getTargetEdges().remove(vertex);
    	 	}
        	//更新所有以目标点为起点的点,在他们的getSourceEdges()集合中去除目标点
    	 	for(L temp2 : targetEdgeSet) {
    	 		Vertex<L> temp2vertex = findVertex(temp2);
    	 		temp2vertex.getSourceEdges().remove(vertex);
    	 	}
    	 	//删除顶点
    	 	vertices.remove(tempVertex);
    	 	flag = true;
        }
        return flag;
    }
    
    @Override public Set<L> vertices() {
    	Set<L> strSet = new HashSet<>();
        for(Vertex<L> vt : vertices) {
     	   strSet.add(vt.getVertex());
        }
        return strSet;
    }
    
    @Override public Map<L, Integer> sources(L target) {
    	
    	Vertex<L> tempVertex = findVertex(target);
        return tempVertex.getSourceEdges();
    }
    
    @Override public Map<L, Integer> targets(L source) {
    	Vertex<L> tempVertex = findVertex(source);
        return tempVertex.getTargetEdges();
    }
    
    /**
     * Find the Vertex from vertices
     * 
     * @param the vertex of Vertex
     * @return the Vertex
     * @throw if can't find,throw new RuntimeException("vertex : no find \n");
     */
    public Vertex<L> findVertex(L vertex) {
    	for(Vertex<L> temp : vertices) {
    		if(temp.getVertex().equals(vertex)){
    			Vertex<L> tempVertex = temp;
    			return tempVertex;
    		}
    	}
    	Vertex<L> tempVertex = new Vertex<L>(vertex);
    	vertices.add(tempVertex);
    	return tempVertex;
    }
    
    // TODO toString()
    @Override
	public String toString() {
    	   return "The vertex number : "+ vertices.size() ;
	}
}

/**
 * TODO specification
 * Mutable.
 * This class is internal to the rep of ConcreteVerticesGraph.
 * 
 * <p>PS2 instructions: the specification and implementation of this class is
 * up to you.
 */
class Vertex<L> {
    
    // TODO fields
	private L vertex;
    private Map<L, Integer> sourceEdges = new HashMap<>();
    private Map<L, Integer> targetEdges = new HashMap<>();
    // Abstraction function:
    //   TODO
    // Representation invariant:
    //   TODO
    // Safety from rep exposure:
    //   TODO
    
    // TODO constructor
    /**
     * Create a vertex with its name
     * 
     * @param name
     *            the identifier of every vertex.
     */
    //建立新点的时候就直接给定vertex
    public Vertex(L vertex)
    {
    	this.vertex = vertex;
    	checkRep();
    }
	
    // TODO checkRep
    private void checkRep() {
        assert vertex != null;
    }
    
    // TODO methods
    /**
     * @return the label of this vertex.
     */
    public L getVertex() {
	    return vertex;
    }
    
    /**
     * @return the source Edges of this vertex.
     */
	public Map<L, Integer> getSourceEdges() {
		return sourceEdges;
	}
	
	/**
     * @return the target Edges of this vertex.
     */
	public Map<L, Integer> getTargetEdges() {
		return targetEdges;
	}
	
    
    
    // TODO toString()
	@Override
	public String toString() {
		return "vertex : " + vertex;
	}
}

3.泛型

其实跟第二部分没有区别,把2中的String全改成L就完事了。(由于最后交的就是L,所以第二部分的代码就是用L写的。

4.诗人的漫步

最好玩的一部分,你需要自己写一个诗,来检验你的代码。就是以之前你写的内个有向图为基础,根据文本诗歌来构造这个有向图,要求和例子看英文网页吧,最后看一下你这个有向图能不能按照人家要求的功能来。代码如下:

/* Copyright (c) 2015-2016 MIT 6.005 course staff, all rights reserved.
* Redistribution of original or derived work requires permission of course staff.
*/

package P1.poet;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
//import java.util.Set;

import P1.graph.Graph;

/**
* A graph-based poetry generator.
* 
* <p>GraphPoet is initialized with a corpus of text, which it uses to derive a
* word affinity graph.
* Vertices in the graph are words. Words are defined as non-empty
* case-insensitive strings of non-space non-newline characters. They are
* delimited in the corpus by spaces, newlines, or the ends of the file.
* Edges in the graph count adjacencies: the number of times "w1" is followed by
* "w2" in the corpus is the weight of the edge from w1 to w2.
* 
* <p>For example, given this corpus:
* <pre>    Hello, HELLO, hello, goodbye!    </pre>
* <p>the graph would contain two edges:
* <ul><li> ("hello,") -> ("hello,")   with weight 2
*     <li> ("hello,") -> ("goodbye!") with weight 1 </ul>
* <p>where the vertices represent case-insensitive {@code "hello,"} and
* {@code "goodbye!"}.
* 
* <p>Given an input string, GraphPoet generates a poem by attempting to
* insert a bridge word between every adjacent pair of words in the input.
* The bridge word between input words "w1" and "w2" will be some "b" such that
* w1 -> b -> w2 is a two-edge-long path with maximum-weight weight among all
* the two-edge-long paths from w1 to w2 in the affinity graph.
* If there are no such paths, no bridge word is inserted.
* In the output poem, input words retain their original case, while bridge
* words are lower case. The whitespace between every word in the poem is a
* single space.
* 
* <p>For example, given this corpus:
* <pre>    This is a test of the Mugar Omni Theater sound system.    </pre>
* <p>on this input:
* <pre>    Test the system.    </pre>
* <p>the output poem would be:
* <pre>    Test of the system.    </pre>
* 
* <p>PS2 instructions: this is a required ADT class, and you MUST NOT weaken
* the required specifications. However, you MAY strengthen the specifications
* and you MAY add additional methods.
* You MUST use Graph in your rep, but otherwise the implementation of this
* class is up to you.
*/
public class GraphPoet {
  
  private final Graph<String> graph = Graph.empty();
  
  // Abstraction function:
  //   TODO
  //build graph poet
  // Representation invariant:
  //   TODO
  //bridge都是小写
  // Safety from rep exposure:
  //   TODO
  //空格,空行
  
  /**
   * Create a new poet with the graph from corpus (as described above).
   * 
   * @param corpus text file from which to derive the poet's affinity graph
   * @throws IOException if the corpus file cannot be found or read
   */
  public GraphPoet(File corpus) throws IOException {
  	
  	//读入文件
      BufferedReader bf = null;
      bf = new BufferedReader(new FileReader(corpus));
      List<String> poemList = new ArrayList<>();
      String templine;
      while ((templine = bf.readLine()) != null) {
      	String[] strArray = templine.split(" ");
          for(int i = 0; i < strArray.length; i++)
          {
          	poemList.add(strArray[i]);
          }
      }
      for (int i = 0; i < poemList.size() - 1; i++) {
      	  int last = 0;
          String s = poemList.get(i).toLowerCase();
          String t = poemList.get(i+1).toLowerCase();
          graph.add(s);
          graph.add(t);
          last = graph.set(s, t, 1);
          graph.set(s, t, last+1);
      }
      bf.close();
      checkRep();
  }
  
  // TODO checkRep
  private void checkRep() {
    for (String vertex : graph.vertices()) {
        int count = 0;
        while (count < vertex.length()) {
            assert (!Character.isUpperCase(count));
            count++;
        }
        assert (!vertex.equals(""));
        assert (!vertex.equals(" "));
        assert (!vertex.equals("\n"));
    }
}
  /**
   * Generate a poem.
   * 
   * @param input string from which to create the poem
   * @return poem (as described above)
   */
  public String poem(String input) {
  	StringBuilder stbr = new StringBuilder();
      String[] strArray = input.split(" ");
      List<String> wordList = new ArrayList<String>(Arrays.asList(strArray));
      Map<String, Integer> sourceEdges;
      Map<String, Integer> targetEdges;
      for (int i = 0; i < wordList.size() - 1; i++) {
          String s = wordList.get(i).toLowerCase();
          String t = wordList.get(i + 1).toLowerCase();
          stbr.append(wordList.get(i)).append(" ");

          targetEdges = graph.targets(s);
          sourceEdges = graph.sources(t);
          int max = 0;
          String bridgeWord = "";
          for (String string : targetEdges.keySet()) {
              if (sourceEdges.containsKey(string)) {
                  if (sourceEdges.get(string) + targetEdges.get(string) > max) {
                      max = sourceEdges.get(string) + targetEdges.get(string);
                      bridgeWord = string;
                  }
              }
          }
          if (max > 0) {
              stbr.append(bridgeWord + " ");
          }
      }
      stbr.append(wordList.get(wordList.size() - 1));
      return stbr.toString();
  }
  
  // TODO toString()
  @Override
  public String toString() {
      return graph.toString();
  }
}

/* Copyright (c) 2015-2016 MIT 6.005 course staff, all rights reserved.
 * Redistribution of original or derived work requires permission of course staff.
 */

package P1.poet;
import java.io.File;
import java.io.IOException;

/**
 * Example program using GraphPoet.
 * 
 * <p>PS2 instructions: you are free to change this example class.
 */
public class Main {
    
    /**
     * Generate example poetry.
     * 
     * @param args unused
     * @throws IOException if a poet corpus file cannot be found or read
     */
    public static void main(String[] args) throws IOException {
        final GraphPoet nimoy = new GraphPoet(new File("src/P1/poet/mugar-omni-theater.txt"));
        final String input = "Test the system.";
        System.out.println(input + "\n>>>\n" + nimoy.poem(input));
        
        System.out.println("*****This is something interesting*****");
        //Graph poerty salm input short and output a whole poem 
        final GraphPoet graphPoet = new GraphPoet(new File("src/P1/poet/mypoem.txt"));
        interesting(graphPoet,"Are Fair");
        interesting(graphPoet,"Parsley thyme");
        interesting(graphPoet,"Remember there");
        interesting(graphPoet,"He mine");
        System.out.print("\n");
        interesting(graphPoet,"Tell shirt");
        interesting(graphPoet,"Parsley thyme");
        interesting(graphPoet,"Without needlework");
        interesting(graphPoet,"Then mine");
        System.out.print("\n");
        interesting(graphPoet,"Tell land");
        interesting(graphPoet,"Parsley thyme");
        interesting(graphPoet,"Between strands");
        interesting(graphPoet,"Then mine");
        System.out.print("\n");
        
        
    }
    
    public static void interesting(GraphPoet graphPoet,String input)
    {
        String output = input;
        for(int i = 0; i < 3; i++ )
        {
        	output = graphPoet.poem(output);
        }
        System.out.println(output);
    }
    
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值