介绍
提供一种方法访问一个容器对象中各个元素,而不需暴露该对象的内部细节
迭代器模式有两个角色,一个是容器,一个是迭代器
由迭代器实现容器的遍历方法,容器通过调用迭代器的封装好的方法进行遍历
迭代其中通常有以下方法:
- boolean hashNext():判断是否已经到达容器的边界。迭代器用游标来记录遍历节点数,通过与容器中的元素数量比较来避免越界
- E next():获取下一个元素值。
或者是
- boolean hashNext()
- void next()
- E currentItem
这两种方式有什么区别?以链表举例好了,如果是单项链表,适合第二种方式,如果使用方式一,在实现安全删除时,会漏掉第一个元素;如果是双向链表则都可以,java 中的 LinkedList 使用的是方式一
使用场景
模板
类图
JDK中的迭代器问题

如果遍历的时候,容器删除了元素,会有以下几种情况
- 删除的是当前游标之后的元素,无影响
- 删除的是当前游标之前的元素,容器中元素的位置就会向前挪
自实现容器使用foreach循环
思路
JDK 有个 foreach 语法糖
它实际上是在编译阶段转为了这个样子
如何使用这个语法糖呢?只需要实现这个接口就可以了
但是这里只是实现语法糖,如果要完全实现上面的效果,还需实现 Iterator 接口,实现 next 与 hasNext 方法
实现
这里的代码是我这篇链表与哨兵中的无哨兵链表实现。实现功能
- 增加
- 删除
- 查找
- foreach 循环
- 安全删除
抽象类
package cn.zjm404.stu.algorithm.list;import java.util.Iterator;/*** @author ZJM*/public abstract class MyLinkedList<T> implements Iterable<T> {protected Node<T> head;protected Node<T> tail;@Overridepublic Iterator<T> iterator() {return new MyLinkedIterator();}static class Node<T> {T value;Node<T> next;Node<T> prev;public Node(T t) {value = t;}}private class MyLinkedIterator implements Iterator<T> {private Node<T> curNode;private Node<T> lastReturn;public MyLinkedIterator() {curNode = head;}@Overridepublic boolean hasNext() {return curNode != null;}@Overridepublic T next() {lastReturn = curNode;curNode = curNode.next;return lastReturn.value;}public T currentItem(){return curNode.value;}@Overridepublic void remove() {if(lastReturn == null){throw new IllegalStateException();}//孤立被删除节点Node<T> del = lastReturn;Node<T> delPrev = lastReturn.prev;//如果删除的节点为首节点if(delPrev == null){head = curNode;curNode.prev = null;}else{delPrev.next = del.next;del.next.prev = delPrev;}del.next = null;del.prev = null;lastReturn = null;}}public abstract void add(T t);public abstract void addFirst(T t);public abstract boolean removeFirst();public abstract boolean remove(T target);public abstract boolean contain(T target);}
无哨兵链表
package cn.zjm404.stu.algorithm.list;public class NoSentryLinkedList<T> extends MyLinkedList<T>{@Overridepublic void add(T t){if(head == null){tail = head = new Node<T>(t);return;}Node<T> newNode = new Node<T>(t);//建立联系newNode.prev = tail;tail.next = newNode;//挪动尾结点tail = newNode;}@Overridepublic void addFirst(T t){if(head == null){tail = head = new Node<T>(t);return;}Node n = new Node(t);n.next = head;head.prev = n;head = n;}@Overridepublic boolean removeFirst(){if(head == null){throw new NullPointerException("空链表异常!");}//如果链表中只有一个节点if(head == tail){head = tail = null;return true;}Node<T> del = head;//孤立节点if(del.next != null){del.next.prev = null;}head = del.next;//删除节点del.prev = null;del.next = null;return true;}@Overridepublic boolean remove(T target){//如果为空链表,则直接返回if(head == null){return false;}//如果删除节点为头节点if(head.value.equals(target)){return removeFirst();}//遍历链表,找到后继节点为target的节点for(Node<T> n = head;n.next != null;n = n.next){if(n.next.value.equals(target)){//删除目标节点Node<T> del = n.next;//孤立节点n.next = del.next;if(del.next != null){del.next.prev = n;}//删除节点del.next = null;del.prev = null;//如果删除的节点为尾节点if(tail == del){tail = n.next;}return true;}}return false;}@Overridepublic boolean contain(T target){for (Node<T> n = head; n != null; n = n.next){if(n.value.equals(target)){return true;}}return false;}}
测试
package cn.zjm404.stu.algorithm.list;public class Client {public static void main(String[] args) {NoSentryLinkedList<String> nl = new NoSentryLinkedList<>();System.out.println("-------插入节点 测试---------------------");nl.add("hello");nl.add("world");nl.addFirst("WORLD");nl.addFirst("HELLO");for (String s : nl) {System.out.println(s);}System.out.println("-------删除 首节点 测试---------------------");nl.removeFirst();for (String s : nl) {System.out.println(s);}System.out.println("-------遍历删除 WORLD 测试---------------------");Iterator<String> iterator = nl.iterator();while(iterator.hasNext()){String cur = iterator.next();if(cur.equals("WORLD")){iterator.remove();continue;}System.out.println(cur);}System.out.println("-------当前状态---------------------");for (String s : nl) {System.out.println(s);}System.out.println("-------删除 world 测试---------------------");nl.remove("world");for (String s : nl) {System.out.println(s);}System.out.println("-------删除 最后一个节点 hello 测试---------------------");System.out.println("删除 hello 是否成功:"+nl.remove("hello"));System.out.println("查找 hello 是否存在:"+nl.contain("hello"));}}
