1. 前情提要
在2.1中,我们创建了IntList类,作为一种列表数据结构。尽管它能完成所要求的全部事情,但是结构不够好,还可以改进。尤其是IntList用的Naked recursive,使代码很难理解。在2.2中我们将再写一个SLList类来改进IntList的不足之处。
2. 改进过程
1. 改名
把名字全改了,看起来更加专业。
public class IntList {
public int first;
public IntList rest;
public IntList(int f, IntList r) {
first = f;
rest = r;
}
...
改成:
public class IntNode {
public int item;
public IntNode next;
public IntNode(int i, IntNode n) {
item = i;
next = n;
}
}
2. 操作性
1. SLList隐藏了NULL:隐含的好处,以后会说。
2. addFirst and getFirst
public void addFirst(int x){
first = new IntNode(x, first);
}
public int getFirst(){
return first.item;
}
由此产生的SLList类更易于使用。对比:
SLList版本:
SLList L = new SLList(15);
L.addFirst(10);
L.addFirst(5);
int x = L.getFirst();
IntList版本:
IntList L = new IntList(15, null);
L = new IntList(10, L);
L = new IntList(5, L);
int x = L.first;
可见在写列表的时候SLList版本可以更无脑,而IntList版本需要一定程度思考。
本质上,SLList 类充当了列表用户和裸递归数据结构之间的中间人。如上文 IntList 版本所述,IntList 用户有可能不希望变量指向 IntList 的中间部分。正如奥维德所说凡人不能直视神明而不死,所以最好还是让 SLList 来充当我们的中间人。
对比这两个图解可以看出SLList和IntList区别
3. Public vs. Private
Private变量和方法只能在同一个.java文件中被调用,其他文件不能调用它,增加了安全性。
4. 嵌套类(Nested Classes)
在java中可以很自然的将一个类放在另一个类里,即嵌套在另一个类中。如果一个类只有一个功能或者只被一个其他类调用过,那就没有必要把它拿出来单独做成一个类。
5. 缓存法
关注size方法,如果列表大小为1000,size耗时2秒,但如果列表大小1,000,000,size耗时会达到2,000秒,为了节约时间,我们可以在SLList类中添加一个size变量来实时跟踪当前的大小,就能节省时间。这种在过程中保存重要数据以加快检索速度的方法称为缓存法。
6. 空列表
2.3 DLList
双向链表,没什么好说的了。
2.4 Arrays
本节讨论java里的数组。
1. 数组的声明:
x = new int [3];
y = new int []{1,2,3,4,5}
int [] z = {6,7,8,9,0}
2. 数组和类的区别
- 数组内元素使用[ ]访问,而类中的元素采用点符号 . 来访问。
- 数组必须是同一类型,类中的元素可以有不同的类型。
这些差异带来的一个特别显著的影响是,[ ] 符号允许我们在运行时指定所需的索引,如int[] x={5,6,7,8}; int k = x[2]; 如此指定列表中某一个元素。链表指定不了。
相比之下,在类中指定字段不是我们在运行时要做的事情。例如,请看下面的代码:
String fieldOfInterest = "mass";
Planet p = new Planet(6e24, "earth");
double mass = p[fieldOfInterest];
2.5 The AList
在本节中,我们将创建一个名为 AList 的新类,它可以用来存储任意长的数据列表,类似于我们的 DLList。与 DLList 不同的是,AList 将使用数组而不是链表来存储数据。
链表走长列表很慢。
Resizing Arrays
java中的数组都是定长度的,定义以后长度不能改变。但是可以用System.
arraycopy来定义一个更长的数组,再把数据复制进去。
但是这种resize相当慢,耗时间耗内存。
Improved Resizing Arrays
拓展数组长度时,用加法拓展size是非常慢的,如果使用乘法或其他几何方法就可以非常快。
Generic ALists
Generic Array泛型的数组在java中不允许。
所以必须改成一个很麻烦的形式
items = (Glorp []) new Object[8];
创建对Glorps的引用数组时:
- (Glorp [ ]) new Object[cap];
这样会导致一个编译器警告,但只需要忽略它即可。
- 为什么不能用new Glorp[cap]:
这样会导致一个"generic array creation"error。
Nulling Out Deleted Items
只有对对象的最后一个引用消失时,java的Garbage Collector才会工作。所以不用的东西及时设置成null。