数据结构,可能我们从接触开始,最先接触到的就是表了,分为链表和顺序表,而顺序表被分配的地址在内存空间中连续,其实也就是我们平常使用的数组,只不过在java这边ArrayList 可以使用泛型设计,不仅可以存储基本的数据类型,也可以存储对象的引用。书中一开始提到了ADT(抽象数据类型),解释为带有一组操作的一些对象的集合。我对这个概念的理解就是,其实在java中就是一些对象而这些对象是用来存储数据的,带有像增删改查这样的操作。为什么叫抽象,就是我们不必知道他们具体的实现,直接调用增删改查这样的操作来操作数据。
比较一下链表和顺序表的优缺点:
1:查找
顺序表明显是在这方面占有优势,知道具体的index就能直接找到所找位置。链表没有索引,所以只能顺着头部或者尾部开始一个节点一个节点这样找下去。
2:添加,删除
这个其实是选择两种不同表的依据。如果是顺序表的话,插入的位置,和删除的位置对时间的开销影响很大,因为顺序表是连续 分配的内存空间,所以他们每个元素之间必须连续,这样如果删除了开头位置的元素,之后位置上的所有元素都要向上移动,如果添加删除在末尾发生,代价就很小了。 而链表此时的优点就显现出来了,因为每个节点在内存中的地址不一定连续,这样添加和删除过程只需改变两个节点之间链的 指向,代价就会很小。而顺序表一旦元素数量超过了一开始分配的空间,就要扩充空间这样代价也是很大的,需要把原来的顺序表复制到一个新的顺序表中,而链表只需要生成新的节点进行添加就ok了。 *********************************************************************************
java.util 这个包中直接为我们提供了ArrayList类,和LinkedList这两个类。根据文档很容易学会这两个类的使用方法。而这本书中着重介绍的不是这两个类的使用方法,而是这两种数据结构的实现方法。这里说明一下这两种数据结构实现过程中用到的方法。这两个类的实现过程中都用到了迭代器,Iterator其实就是一个java的接口,实现了这个接口就可以对集合进行简单的遍历。而接口其实就是一种规约,规定了名字却没有具体实现,把实现这个接口的工作交给完成这个接口的子类。所以如果我自己去分别 实现ArrayList 和 LinkedList那么对于iterator中的hasNext()方法,具体的实现方法是不一样的。并且接口类型的变量可以存储实现这个接口的子类,这样对client就可以做到信息的屏蔽,每次发生改动,client端的代码不需要修改,他们仍然调hasNext() 方法。因为代码有点长,暂时没有找到源码,就不贴出来了,有书的可以自己对照着书看。
说一下要点:
1:在MyArrayList 和MyLinkedList 当中分别用了一个内部类ArrayListIterator和LinkedListIterator 实现Iterator 接口,这样根据两个连表的不同特点用不同的方法去实现接口中的方法。这里提到了内部类,内部类最常见的地方应该是在设定监听器的时候,语法确实有些古怪。我们可以把这个内部类看成是外部类的一个成员变量,如果把内部类设置成private 那么内部类当中的属性设置成private 或者public 都无所谓,因为这个内部类不被外部类以外 的任何类可见,当然也就谈不上去获取内部类的属性了。而内部类对外部类的属性和方法是具有可见性的。这样就可以通过这个接口对list中的元素进行操作了。
2:在设计这个MyLinkedList 过程中考虑了一种情况就是,在我们调用next()方法去获取下一个节点时,恰好下一个节点被删除,或者被添加。一开始我觉得添加或者删除了,继续返回新的不就可以了。后来发现这是iterator使用过程中要注意的一点,就iterator remove的是next()返回的项,必须再次调用next()然后才能调用remove,目前还不大明白java这样设计的目的,应该是有它的优点的。那么为了防止这种在迭代过程中发生添加删除,所以在MyLinkedList中就用一个modCount 来记录这个List同时在内部类LinkedListIterator 中也保存有一个modCount 每次发生add remove clear 的时候就增加该flag的值,同时再设置一个flag叫okToRemove 这个值在remove 后设置为false 然后发生过next()之后再设置为true,这样就保证每一次remove都发生在next()后边,就符合该接口的要求了。其实在MyLinedList当中有好几个重载的remove方法,Iterator的remove方法不带参数, 所以在调用Iterator的remove方法时要检测是否调用了外部类的remove(parameter)方法,所以外部类每次add或者remove都要改变modCount,所以检测LinkedListIterator中的modCount 和外部类的modCount是否一致,如果一致,说明没有通过外部类 的remove方法进行添加删除,而调用Iterator的remove方法其实是调用外部类的remove方法,这样内外部类的modCount会一 直保持一致。
其实我们没必要去自己实现一个链表顺序表,而这种检错方法使我们可以借鉴的。没想到一个简单的表中间能挖掘出这么多隐藏的东西,书果然需要耐心的读,坚持!