Part5:Grid Data Structures

Part5:Grid Data Structures

Step1:The AbstractGrid Class

Set 10

The source code for the AbstractGrid class is in Appendix D.

  1. Where is the isValid method specified? Which classes provide an implementation of this method?

    这个题目在第二阶段的part2有提到过一点,isValid()函数在Grid接口里面声明,在它的接口直接继承的两个继承类里面实现了两个不同的版本:

    public boolean isValid(Location loc)//BoundedGrid版本
    {
        return 0 <= loc.getRow() && loc.getRow() < getNumRows()
                && 0 <= loc.getCol() && loc.getCol() < getNumCols();
    }
    public boolean isValid(Location loc)//UnboundedGrid版本
    {
        return true;
    }
    
  2. Which AbstractGrid methods call the isValid method? Why don’t the other methods need to call it?

    函数方法getValidAdjacentLocations 调用了isValid 方法。这个是最直接的调用,而其他的一些方法没有直接调用isValid函数,但是它们调用了getValidAdjacentLocations方法,在valid的判断当中其实也是间接地实现了调用,例如getEmptyAdjacentLocations方法和getOccupiedAdjacentLocations方法,还有getNeighbors方法不是直接调用了isValid方法,而是调用了getOccupiedAdjacentLocations方法,之所以调用这些函数的原因是,他们内部的需求在逐级递进,例如说开头判断是否合理,后面一句开头的条件进行判断是否有合理的位置坐标,以及下一个位置的位置坐标等等,这是一个逐渐进益的过程。

  3. Which methods of the Grid interface are called in the getNeighbors method? Which classes provide implementations of these methods?

    首先我们看看AbstractGrid里面的函数情况:

    for (Location neighborLoc : getOccupiedAdjacentLocations(loc))
                neighbors.add(get(neighborLoc));
            return neighbors;	
    

    这个函数它调用了接口里面的get()函数跟getOccupiedAdjacentLocations()函数,后者是在本文件之下完成定义的,而前者是在该类的两个继承类BoundedGridUnboundedGrid 当中实现的。

  4. Why must the get method, which returns an object of type E, be used in the getEmptyAdjacentLocations method when this method returns locations, not objects of type E?

    get()函数的作用是:返回在网格中的指定对象(Object)的引用,如果说该引用为空的话,也就是所在网格当中其实该对象并不存在,所以说我们的get函数是用来判断指定的位置是否存在对象的依据,getEmptyAdjacentLocations方法它调用了当前实现的get()函数来检测目标位置是否存在一个单位,如果存在的话跳过去,不存在的话就把当前位置的坐标位置加入到可执行的队列当中(代表该位置是空的)。这个get()函数是检测当前位置是否为空的唯一可用标准。

  5. What would be the effect of replacing the constant Location.HALF_RIGHT with Location.RIGHT in the two places where it occurs in the getValidAdjacentLocations method?

    先看看代码:

    public ArrayList<Location> getValidAdjacentLocations(Location loc)
        {
            ArrayList<Location> locs = new ArrayList<Location>();
    
            int d = Location.NORTH;
            for (int i = 0; i < Location.FULL_CIRCLE / Location.HALF_RIGHT; i++)
            {
                Location neighborLoc = loc.getAdjacentLocation(d);
                if (isValid(neighborLoc))
                    locs.add(neighborLoc);
                d = d + Location.HALF_RIGHT;
            }
            return locs;
        }
    

    这个函数的功能是,找到Loc位置周围可能的八个位置的合理网格单元,这的话八个位置就是字\(NORTH\)开始每\(HALF\_RIGHT\)一次出现的位置,总共是8个,那么如果把\(Location.HALF\_RIGHT\)换成\(Location.RIGHT\),那么整个坐标转一周也就是4次,也就是方向只剩下东南西北,那么能够找到的可能位置就只有这4个方位了,而不是8个。

Step2:The BoundedGrid Class

Set 11

The source code for the BoundedGrid class is in Appendix D.

  1. What ensures that a grid has at least one valid location?

    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];
        }
    

    如果当前的地图不合理,构造函数会给出一个警告,以保证我们在执行的时候最少是有一个位置是合理的。

  2. How is the number of columns in the grid determined by the getNumCols method? What assumption about the grid makes this possible?

    // Note: according to the constructor precondition, numRows() > 0, so
    // theGrid[0] is non-null.
    return occupantArray[0].length;
    

    该方法返回occupantArray第一行的列数,以保证我们接下来的判断当中网格至少是一个单位的网格(也就是至少一行一列)。

  3. What are the requirements for a Location to be valid in a BoundedGrid?

    地图的笛卡尔坐标的表示是从\((0,0)\)开始的,所以我们在构建有边图的时候,需要确保我们的给出位置的信息要满足:\(max\_row\geq{rows}\geq 0\)而且\(max\_col\geq{cols}\geq 0\).

In the next four questions, let r = number of rows, c = number of columns, and n = number of occupied locations.

  1. What type is returned by the getOccupiedLocations method? What is the time complexity (Big-Oh) for this method?

    函数返回一个ArrayList<Location>列表,时间复杂度满足\(O(r\ast{c})\),因为要找到被占据的位置我们需要了解每个位置的情况,所以说在一个二维的数组里面我们需要执行一个遍历的操作,所以会时间复杂度就是遍历操作的复杂度。

  2. What type is returned by the get method? What parameter is needed? What is the time complexity (Big-Oh) for this method?

    前面提到过了,一个get()函数返回的内容是一个\(E\)类型的对象,用来检测该位置是否存在一个对象,它的参数是一个Location类型的变量,该函数是线性操作,没有涉及遍历的操作,在合理的笛卡尔坐标上面(一个)操作,所以时间复杂度\(O(1)\)

  3. What conditions may cause an exception to be thrown by the put method? What is the time complexity (Big-Oh) for this method?

    public E put(Location loc, E obj)
        {
            if (!isValid(loc))
                throw new IllegalArgumentException("Location " + loc
                        + " is not valid");
            if (obj == null)
                throw new NullPointerException("obj == null");
    
            // Add the object to the grid.
            E oldOccupant = get(loc);
            occupantArray[loc.getRow()][loc.getCol()] = obj;
            return oldOccupant;
        }
    

    当前的位置信息不是isValid()的时候,抛出一个异常,当前的Object为空的时候抛出一个异常,执行的步骤是线性的一个点,所以时间复杂度满足\(O(1)\)

  4. What type is returned by the remove method? What happens when an attempt is made to remove an item from an empty location? What is the time complexity (Big-Oh) for this method?

    当前方法返回的是一个\(E\)类型的Object对象,如果尝试删除一个空的位置,那么当前方法会抛出一个异常,同理,时间复杂度还是\(O(1)\)

  5. Based on the answers to questions 4, 5, 6, and 7, would you consider this an efficient implementation? Justify your answer.

    根据时间复杂度来看的话,我们的实现基本上处于一个高效的状态,基本上所有的实现都满足一个\(O(1)\)的需求,唯一不一样的是getOccupiedLocations方法,它的时间复杂度会稍微有点大。

Step3:The UnboundedGrid Class

Set 12

The source code for the UnboundedGrid class is in Appendix D.

  1. Which method must the Location class implement so that an instance of HashMap can be used for the map? What would be required of the Location class if a TreeMap were used instead? Does Location satisfy these requirements?

    Location类必须实现hashCodeequals方法,当equals方法判断两个位置一样时候,我们的哈希函数必须具备同样的键值,并且尽量做到减少哈希冲突,Location类实现比较的接口。因此,Location必须实现compareTo方法。当调用equals方法时测试的两个位置相等的时候,compareTo方法返回0。Location类满足所有要求。

  2. Why are the checks for null included in the get, put, and remove methods? Why are no such checks included in the corresponding methods for the BoundedGrid?

    unboundgrid使用HashMap作为其数据结构来保存网格中的项。全部非空位置在无界网格中有效。unboundGrid的isValid方法始终

    返回true,因为它没有边界。在Map对象中,key的合法值是空,在unboundgrid中,null不是有效位置。因此,getputremove必须检查location参数,当参数为空时抛出NullPointerException

    在使用有界网格中的Location的时候,我们应当使用isValid(),如果isValid方法中的location参数为null,则尝试访问

    getRow()将导致抛出NullPointerException。如果编写的代码在调用get、put和remove之前未调用isValid方法方法,尝试访问位置getRow()在这些方法中也会导致抛出NullPointerException。

    public E put(Location loc, E obj)
        {
            if (loc == null)
                throw new NullPointerException("loc == null");
            if (obj == null)
                throw new NullPointerException("obj == null");
            return occupantMap.put(loc, obj);
        }
    
  3. What is the average time complexity (Big-Oh) for the three methods: get, put, and remove? What would it be if a TreeMap were used instead of a HashMap?

    get``、putremove```的平均时间复杂度为\(O(1)\)。如果使用TreeMap而不是HashMap,则平均时间复杂度为\(O(log_2n)\),其中n

    是网格中已占用的位置数。

  4. How would the behavior of this class differ, aside from time complexity, if a TreeMap were used instead of a HashMap?

    大多数情况下,getOccupiedLocations方法将以不同的顺序返回occupants

    HashMap中的键(位置)基于使用哈希表的大小。当键集被访问时,访问该键的顺序

    取决于它在哈希表中的位置。HashMap将它的key存储在一个平衡的二叉搜索树中,并使用中序遍历遍历遍历该树。

    键集中的键将按升序被访问。

  5. Could a map implementation be used for a bounded grid? What advantage, if any, would the two-dimensional array implementation that is used by the BoundedGrid class have over a map implementation?

    map可以被用来实现BoundedGrid,如果使用HashMap的话,那么实现该类的方法getOccupiedLocations的时间复杂度将会到达\(O(n)\),在向通的情况之下map将会使用更多的内存,因为map需要存储的是Object包括它的Location,而我们的二维向量就不一样了,他只需要存储Object,位置的话,二维向量的下标会给出索引,不需要特意存储。

    public ArrayList<Location> getOccupiedLocations()
        {
            ArrayList<Location> a = new ArrayList<Location>();
            for (Location loc : occupantMap.keySet())
                a.add(loc);
            return a;
        }
    
posted @ 2020-10-26 10:11  Marvel_Iron_Man  阅读(97)  评论(0)    收藏  举报