线性表中迭代器的内部实现(Iterator、ListIterator)

来源:互联网 发布:linux root修改密码 编辑:程序博客网 时间:2024/05/12 06:48
      迭代器(Iterators)是对数据集进行遍历的对象,在遍历过程中,可以查看、修改、添加以及删除元素。Java类库中有两个有关迭代器的接口:Iterator和ListIterator,它们为迭代器指定了方法,可以将迭代器方法添加到ADT线性表的操作中,也可以将迭代器定义为一个与ADT线性表相互作用的单独的类。Java中还提供了一个Iterable接口,该接口的Iterator方法返回一个标准的Iterator实现。

     独立的迭代器与内部的迭代器

     独立类迭代器必须通过ADT的公用方法来访问ADT的数据,如果某些ADT,如堆,没有提供足够的数据访问方法,使得不能实现这种迭代器。另外,独立类迭代器比其他类型的迭代器的运行时间要长。但是,独立类的迭代器的实现往往比较简单。内部类迭代器可以直接访问ADT的数据,因此它往往比单个类的迭代器运行速度快。其实现单价也更大。迭代器的方法为什么要在自己的类中?因为如果迭代器的方法在ADT中,某个时候只能有一个遍历,而且,需要使用一些不属于接口Iterator的操作来初始化遍历。

    Iterator接口

    Java类库在java.util包中提供了该接口。Iterator接口只描述了3个方法:hasNext、next和remove。这些方法从第一个数据元素开始遍历数据集。

    hasNext():测定迭代器是否完成遍历并越过数据集中的最后一个元素,若是,则返回false,否则返回true.

    next():提取集合集中当前(下一个)元素并迭代前进一个位置

    remove():从数据集中删除next()返回的最后一个元素,此后调用next()的行为将与删除前一样

   下面是iterator在以数组方式实现的线性表中的内部实现,在以链表实现的线性表类似。就是用nextNode=nextNode.next代替nextIndex++,判断hasNext(),就是判断nextNode是否为空。

    

/** * 在数组方式实现的线性表中,作为内部类实现其迭代器,java类库arrayList中已实现其迭代器Iterator * @key * @author S.M.Q  * 2014年9月14日下午8:04:58 */private class IteratorForArrayList implements Iterator<T>{private int nextIndex;private boolean isCalledNext;IteratorForArrayList(){nextIndex=0;isCalledNext=false;}/** * 判断是否到该线性表的最后一个元素,只要判断下一个元素的索引是否小于该线性表的长度 */public boolean hasNext(){return nextIndex<length;}/** * 返回下一个元素,并将索引往前进一步 * 为防止数组越界,判断一下当前索引是否小于线性表的长度,否则抛出异常 */public T next(){if(nextIndex<length){isCalledNext=true;return entry[nextIndex++];}elsethrow new NoSuchElementException("no illegal exception");}/** * 删除的当前元素,故该方法只能在调用next之后调用,此处用isCalledNext标识next是否调用 * 其他调用则派出非法异常 */public void remove(){if(isCalledNext){  MyArrayList.this.remove(nextIndex);  nextIndex--;  isCalledNext=false;}elsethrow new IllegalStateException(" illegal state exception");}}
      ListIterator接口

      该接口是Java类库中提供的另一个迭代器接口,这种迭代器允许双向遍历线性表,并且在遍历过程中可以修改线性表。除了Iterator接口说明的3个方法hasNext、next和remove之外,ListIterator还含有诸如hasPrevious、previous、add和set方法

      hasPrevious:检查迭代是否已完成遍历并到达数据集中的第一个元素之前

      previous:提取线性表中前一个元素并将迭代向前移动一个

     add:向线性表中插入元素,插入位置在next()可能返回的元素之前,previous可能返回的元素之后,插入之后,调用previous()将返回新元素,而调用next()将与插入前的一样

     set:替换线性表中由next()或previous()刚返回的最后一个元素

     下面是以数组方式实现的线性表,ListIterator作为内部类的实现,链表方式与数组方式类似:

   

/** * 数组方式实现的线性表中,作为内部类实现其迭代,java在arrayList中已经实现listIterator * @key * @author S.M.Q  * 2014年9月14日下午9:02:28 */private class ListIteratorForArrayList implements ListIterator{private int nextIndex;private Move lastMove;private boolean isMoveOrSetLegal;/** * 该迭代器可以向前向后,所以只能用一个索引,通过增减索引实现其向前或者向后 * 向前或向后操作略有不同,故用一个枚举来记录其动作 * set或remove都是对当前元素进行操作,所以要设置一个标示,看是否能进行set或remove操作 */ListIteratorForArrayList(){nextIndex=0;isMoveOrSetLegal=false;lastMove=null;}/** * 与Iterator的hasNext类似 */public boolean hasNext(){return nextIndex<length;}/** * 与Iterator的next类似 */public T next(){if(hasNext()){isMoveOrSetLegal=true;lastMove=Move.NEXT;return entry[nextIndex++];}elsethrow new NoSuchElementException("no such element exception!");}/** * 查看当前索引是否大于0,如果大于0,说明当前元素不是位于线性表的第一个 */public boolean hasPrevious(){return nextIndex>0;}/** * 返回当前元素的前一个元素,并将迭代向前推进一个 * 记录相关特征,lastMove和nextIndex */public T previous(){if(hasPrevious()){isMoveOrSetLegal=true;lastMove=Move.PREVIOUS;nextIndex--;return entry[nextIndex];}elsethrow new NoSuchElementException("no such element exception!");}/** * 移除当前元素,remove操作需要在调用next()和previous之后。才能进行操作,故根据isMoveOrSetLegal的状态来 * 进行是否可以进行remove操作,我实现的MyArrayList实现的remove函数的参数,是该元素的位置,而调用过next之后,当前索引加1, * 调用previous之后,当前索引需要加1,才是位置(因为nextIndex是从0开始的) * 最后由于移除掉一个元素,当前的索引需要自减1,因为线性表的长度减一了 */public void remove(){if(isMoveOrSetLegal){isMoveOrSetLegal=false;if(lastMove==Move.NEXT)MyArrayList.this.remove(nextIndex);else{  nextIndex++;    MyArrayList.this.remove(nextIndex);}nextIndex--;}elsethrow new IllegalStateException("illegal operation!");}/** * 返回下一个索引 */public int nextIndex(){int result;if(hasNext())result=nextIndex;elseresult=length;return result;}/** * 返回前一个索引 */public int previousIndex(){int result;if(hasPrevious())result=nextIndex-1;elseresult=-1;return result;}         /**          * 根据标识,看是否能操作set,否则抛出异常          * 调用线性表内部的set方法          */@Overridepublic void set(Object e) {// TODO Auto-generated method stubif(isMoveOrSetLegal){if(lastMove==Move.NEXT)MyArrayList.this.replace(nextIndex,(T)e);elseMyArrayList.this.replace(nextIndex+1,(T)e);}elsethrow new IllegalStateException("illeagl operation");}         /**          * 同样也是调用线性表内部的add方法          * 然后索引需要自增1,因为线性表的长度增1了          */@Overridepublic void add(Object e) {isMoveOrSetLegal=true;nextIndex++;MyArrayList.this.add(nextIndex,(T)e);}}

     

0 0
原创粉丝点击