Iterable是说这个对象支持iterate操作,是可iterate的,需要遍历的话,给你返回一个iterator进行遍历
Iterator对应具体的一次遍历,核心数据是遍历指针
Iterator 封装了目标被遍历对象,并维护遍历状态,(可能不只是简单的遍历指针,因为被遍历对象不一定是线性结构,比如树,遍历状态是stack的状态和当前节点root)
其他辅助状态:
flag: 标志当前是否有item 取出来了还未被取走
current: 存放下一个item
boolean hasNext()
如果flag 为true, 则直接返回true,
否则尝试取下一个item, 如果取到了,放到current里,设置flag为true,如果流结束了都没有item了,flag一直会为false, 最后返回flag。
Item next()
要先看flag, flag为真才返回item,
注意:1)flag 和current可以合而为一, flag用 current是否为null代表,2)必须hasNext(), 之后next()结合使用。
根据需求不同,有2种实现方式
1)预先准备好下一个数据current,一般是在hasNext()里准备,next()只是返回current并置current为null
2)不预先准备,没有current变量。hasNext()判断是否还有数据,next真正往前走返回数据,如BSTIterator
class BSTIterator {
public:
BSTIterator(TreeNode *root) {
this->root = root;
}
/** @return whether we have a next smallest number */
bool hasNext() {
return root || !s.empty();
}
/** @return the next smallest number */
int next() {
while (root || !s.empty()) {
if (root) {
s.push(root);
root = root->left;
} else {
root = s.top(); s.pop();
int ret = root->val;
root = root->right;
return ret;
}
}
}
private:
TreeNode *root;
stack<TreeNode*> s;
};
条件过滤Iterator
标准的预先准备current的方式:因为要判断是否符合条件
class FilterIterator<T> implements Iterator<T> {
private Iterator<T> it;
private T current;
private Predicate<T> filter;
public FilterIterator (Iterator<T> sourceIterator, Predicate<T> predicate){
it = sourceIterator;
current = null;
filter = predicate;
}
@Override
public boolean hasNext() {
if (current != null) return true;
while (it.hasNext()) {
T temp = it.next();
if (filter.test(temp)) {
current = temp;
return true;
}
}
return false;
}
@Override
public T next() {
T ret = current;
current = null;
return ret;
}
}
支持peek的 Iterator
两种方式结合
class PeekingIterator implements Iterator<Integer> {
private Iterator<Integer> it;
Integer current;
public PeekingIterator(Iterator<Integer> iterator) {
// initialize any member here.
this.it = iterator;
current = null;
}
// Returns the next element in the iteration without advancing the iterator.
public Integer peek() {
if (null != current) return current;
current = it.next();
return current;
}
// hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
@Override
public Integer next() {
if (null != current) {
Integer ret = current;
current = null;
return ret;
}
else {
return it.next();
}
}
@Override
public boolean hasNext() {
return current != null || it.hasNext();
}
}