Part 5
set 10
在GridWorldCode/framework/info/gridworld/grid路径下的grid.java文件中
-
在Grid接口中定义,在 BoundedGrid 和 UnboundedGrid类中实现。
-
getValidAdjacentLocation()方法中直接调用了IsValid()方法,而其它方法如getEmptyAdjacentLocations()方法和getOccupiedAdjacentLocations方法都通过调用getValidAdjacentLocation()方法间接调用了IsValid()方法。
-
getNeighbors()方法调用了Grid接口中的get() 方法和getOccupiedAdjacentLocations() 方法。BoundedGrid 和 UnboundedGrid类实现了get()方法,而AbstractGrid类实现了getOccupiedAdjacentLocations()方法。
public ArrayList<E> getNeighbors(Location loc) { ArrayList<E> neighbors = new ArrayList<E>(); for (Location neighborLoc : getOccupiedAdjacentLocations(loc)) neighbors.add(get(neighborLoc)); return neighbors; }
-
因为get()方法返回存储在grid中给定位置的引用,如果不存在对象则返回null。而getEmptyAdjacentLocations()方法调用get()方法就是为了判断给定位置是否为空或者是被占用。
-
getValidAdjacentLocations()方法返回当前位置八个方向上的所有Valid的位置,如果由Location.HALF_RIGHT 变为Location.RIGHT也就是说每次向右旋转45度变为旋转90度,则可以探测到的可以返回的Valid位置会比原来减少一半,只有东、南、西、北四个方向上的Valid位置会被返回。
Set 11
在GridWorldCode/framework/info/gridworld/grid路径下的BoundedGrid.java文件中
-
由下面的构造函数可以看出,如果行数或列数小于等于0,会抛出IllegalArgumentException()异常,这保证了grid至少有一个valid位置。
public BoundedGrid(int rows, int cols) { if (rows <= 0) throw new IllegalArgumentException("rows <= 0"); if (cols <= 0) throw new IllegalArgumentException("cols <= 0"); occupantArray = new Object[rows][cols]; }
-
因为构造函数保证了grid至少有一个valid位置,即occupantArray[0]一定存在,而返回 occupantArray[0].length就可以确定其它行的列数与occupantArray[0]相同。
public int getNumCols() { // Note: according to the constructor precondition, numRows() > 0, so // theGrid[0] is non-null. return occupantArray[0].length; }
-
在isValid()方法中定义了一个valid位置的特点:该位置的行、列数都大于0而小于grid的总的行、列数。
public boolean isValid(Location loc) { return 0 <= loc.getRow() && loc.getRow() < getNumRows() && 0 <= loc.getCol() && loc.getCol() < getNumCols(); }
-
返回一个包含n个被占用的位置 ArrayList,因为要grid中访问r行、c列的所有位置,复杂度(Big-Oh)为r*c。
-
根据在BoundedGrid类中实现的方法get:
会返回一个E类型,也就是任意可以在occupantArray中存储的类型的值。
需要一个参数Location。
(Big-Oh)为1
public E get(Location loc){ if (!isValid(loc)) throw new IllegalArgumentException("Location " + loc + " is not valid"); return (E) occupantArray[loc.getRow()][loc.getCol()]; }
-
根据实现的方法put(Locaion loc,E obj):
当loc不在grid中或者obj为空时会抛出异常。
(Big-Oh)为1
if (!isValid(loc)) throw new IllegalArgumentException("Location " + loc + " is not valid"); if (obj == null) throw new NullPointerException("obj == null");
-
根据实现的方法remove(location loc)
返回一个E类型的在loc位置存储的grid elements。
null被存储在相应的位置并返回,并不会抛出异常。
(Big-Oh)为1
public E remove(Location loc){ if (!isValid(loc)) throw new IllegalArgumentException("Location " + loc + " is not valid"); // Remove the object from the grid. E r = get(loc); occupantArray[loc.getRow()][loc.getCol()] = null; return r; }
-
答案4、5、6、7中提到的四种方法实现只有一个getOccupiedLocations()的复杂度为r*c,其它都为1,可以认为这是一个有效的接口实现。同时获取一个occupantArray二维数组中的元素的的复杂度也是1,因此BoundedGrid类的继承以及接口方法的实现是efficient implementation。
Set 12
在GridWorldCode/framework/info/gridworld/grid路径下的BoundedGrid.java、Location.java文件中
-
Location类需要实现hashCode()、equals()方法才可以让一个HashMap应用到map。因为当调用equals()方法时,hashCode()方法必须为两个测试为true的位置返回相同的值。Location类实现compareTo()的接口。因此,必须实现compareTo方法才能使Location类成为非抽象类。
TreeMap要求地图的key值具有可比性,而compareTo()方法实现了key值的比较。
-
UnboundedGrid类使用HashMap作为数据存储结构来保存grid中的所有元素,所有非null位置都是有效的位置,所以isValid()始终返回true。在Map对象中,null为合法键值,在UnboundedGrid中,null不是有效位置。因此,UnboundGrid方法get、put和remove必须检查location参数,并在参数为null时抛出NullPointerException异常。
访问BoundedGrid类中的Occupportarray之前调用isValid方法。如果isValid方法中的location参数为null,则尝试访问位置getRow()等方法将导致引发NullPointerException。如果编写的代码在调用get、put和remove方法之前未调用isValid方法,则尝试访问位置getRow这些方法中的()还将导致引发NullPointerException。
//valid函数始终返回true
public boolean isValid(Location loc)
{
return true;
}
public E get(Location loc)
{
if (loc == null)
throw new NullPointerException("loc == null");
return occupantMap.get(loc);
}
-
方法get、put和remove的复杂度均为1,所以平均复杂度Big-Oh也为1。
设n为所有被占用的位置,则平均复杂度将变为O(lg n)。
-
大多数情况下,getOccupiedLocations()方法将以不同的顺序返回被占用的位置,HashMap中的键根据使用键的hashcode和size将计算的索引放入哈希表中。遍历键集时访问键的顺序取决于它在哈希表中的位置。树映射将它的键存储在一个平衡的二叉搜索树中,并使用有序遍历遍历遍历该树。将按照Location类实现的的compareTo()方法定义的升序(row major order)访问键集中的键。
-
map可以在BoundedGrid中实现,如果一个HashMap被应用到BoundedGrid,getOccupiedLocations()方法的平均时间复杂度将是O(n),其中n是网格中的被占用的位置。
如果BoundedGrid所有的位置都非空,则HashMap需要更多的内存, 因为map保存了每个位置的对像以及location。而二维数组仅仅保存对象,而location通过getRow()、getColum()方法来获取。