实验一 线性结构
实验内容
- 1.ArrayList和LinkedList测试:
查看ArrayList和LinkedList的Java API帮助文档,参考http://www.cnblogs.com/rocedu/p/4837092.html 用Junit对ArrayList和LinkedList的方法进行测试,要尽量覆盖正常情况,异常情况,边界情况 - 2.分别用Java的ArrayList和LinkedList实现有序线性表的合并:aList,bList都是非递减线性表,合并后也是非递减
public static List<? extends Comparable> mergeSortedList(List<? extends Comparable> aList, List<? extends Comparable> bList)
测试mergeSortedList的正确性,要尽量覆盖正常情况,异常情况,边界情况。 - 3.参考Java Foundation 3rd 第15.6节,用数组实现线性表List用JUnit或自己编写驱动类对自己实现的ArrayList进行测试。
- 4.参考Java Foundation 3rd 第15.7节,用链表实现线性表List用JUnit或自己编写驱动类对自己实现的LinkedList进行测试。
- 5.参考http://www.cnblogs.com/rocedu/p/7483915.html对Java的ArrayList,LinkedList按要求进行源码分析。
实验步骤
实验1:
根据需求,首先查找帮助文档中ArrayList和LinkedList类的方法,根据要求测试add、isEmpty、remove、contains方法,首先建立一个数组,在里面放入5个元素。测试是否为空,返回false;使用add方法添加"book",检查数组中是否含有该要素;先add一个元素“book”,再调用remove方法删去这个元素,检最后查是否含有“book”;使用element方法来查唯一元素"book"验证contains方法,返回true。
实验2:
我的思路是先创建两个列表,两个列表可以放不同的元素,例如数字和String类型,比如我先创一个列表A,在其中中放入数字1和3,再创一个列表B,放入数字2和4,编写代码将数字个数少的列表插入数字多的列表,进行比较两列表的元素,完成插入排序,然后将结果返回到列表C,从而完成两列表的合并。最后编写测试代码进行测试。
实验3:
由于实验3要求编写驱动类对ArrayList方法进行测试,这和前几天的Bag类基本相同,所以可以参考我的Bag类博客
实验4:;
根据题意可知需要用LinkedList来实现List方法,有isEmpty、add、remove方法。为了方便测试我引入了element方法,即获取列表中的第一个元素。首先实现isEmpty,放入若干个数字,测试返回false;然后使用add方法加入"666",使用element获取第一个元素是否为“666”,测试成功;测试remove先放入一个“666”和“Java”,再用remove删去“666”,然后使用element获取第一个元素,返回"Java",测试成功。
实验5:源码分析
通过查找src.zip
解压包util/ArrayList文件夹目录,使用IDEA打开。找到源码后首先ArrayList引用了AbstractList类,这个提供 List 接口的骨干实现,以最大限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作。然后就出现了很多看不懂的代码,但是我挑选了我们常用的一些方法的实现作为案例分析:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
通过查看这段代码可以知道一个add方法的基本思路是首先这个容器的容量要加1,以表示添加了一个元素,然后把e元素附加到该列表,整个过程十分精炼。插入指定元素在指定的位置在这列表。移动当前处于该位置的元素(如果有的话)和右边的任何后续元素(添加一个到它们的索引)。
但是针对这段代码我有一个疑问,比如我在elementData中放入一个元素,按照这段代码,它被放入了elementData[1]中,但是elmentData[0]不就没有东西吗?如果获取列表中的第一个元素的话不就获取的是elementData[0]吗?通过做实验,elementData[size++] = e;
这段代码讲的其实是先放入元素到elementData[0]里然后在size++,所以不是先完成size++。
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
然后分析代码中的remove方法的实现,index是要删除的元素的索引,oldValue是列表中要删除的元素,思路是在列表中指定位置删除元素。所有后续元素左移(减去一个从指数)。
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
contains方法利用indexOf来实现,查阅后发现原理是建立一个循环,对列表里面的元素进行逐一比较,返回的第一个出现的指定元素的索引在这份名单中,如果此列表不包含元素。返回最低的索引。后面翻阅contains方法时就调用了indexOf来检查列表中是否含有某元素。
感受:通过查读源代码我总结出一些规律,1.任何类的任何方法都是由最基础的程序设计语言实现的 2.编写源代码的程序员在编写源代码时的思维十分清晰,我是真的佩服,这也给后生们写代码提供了思路和灵感,可以学到很多有用的编程方法和设计模式 3.查阅源代码可以对出现的bug实行有针对性的debug,知道具体哪个地方出错