独立的迭代器与内部的迭代器
独立类迭代器必须通过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++];
}
else
throw new NoSuchElementException("no illegal exception");
}
/**
* 删除的当前元素,故该方法只能在调用next之后调用,此处用isCalledNext标识next是否调用
* 其他调用则派出非法异常
*/
public void remove()
{
if(isCalledNext)
{
MyArrayList.this.remove(nextIndex);
nextIndex--;
isCalledNext=false;
}else
throw 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++];
}else
throw 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];
}else
throw 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--;
}else
throw new IllegalStateException("illegal operation!");
}
/**
* 返回下一个索引
*/
public int nextIndex()
{
int result;
if(hasNext())
result=nextIndex;
else
result=length;
return result;
}
/**
* 返回前一个索引
*/
public int previousIndex()
{
int result;
if(hasPrevious())
result=nextIndex-1;
else
result=-1;
return result;
}
/**
* 根据标识,看是否能操作set,否则抛出异常
* 调用线性表内部的set方法
*/
@Override
public void set(Object e) {
// TODO Auto-generated method stub
if(isMoveOrSetLegal)
{
if(lastMove==Move.NEXT)
MyArrayList.this.replace(nextIndex,(T)e);
else
MyArrayList.this.replace(nextIndex+1,(T)e);
}else
throw new IllegalStateException("illeagl operation");
}
/**
* 同样也是调用线性表内部的add方法
* 然后索引需要自增1,因为线性表的长度增1了
*/
@Override
public void add(Object e) {
isMoveOrSetLegal=true;
nextIndex++;
MyArrayList.this.add(nextIndex,(T)e);
}
}