zoukankan      html  css  js  c++  java
  • 迭代器(iterator)

    迭代器(iterator)

     

    如果我们想遍历数组,这很容易,因为可以用数组的下标跟踪所在的位置,然而在链表中,节点没有这样的下标,怎样才能提供给链表用户类似于数组下标的东西呢?这就是迭代器(iterator)的作用。

    我们知道添加到链表中的数据(data),都会包装成一个节点(node),节点之间通过引用保存了先后关系(pre、next)。但是由于在获取数据时(如getFirst),返回的直接是数据(data),数据本身没有其之后数据的引用,因此无法遍历。

    但是node存在这样的引用,如果我们直接把node返回给用户,让用户自己从node获取数据,不就可以实现遍历了吗?我们可以提供一个getFirstNode()方法,然后按照类似以下代码片段进行遍历:

    1. Node node=linkedList.getFirstNode();
    2. while(node!=null){
    3.      Object data=node.getData();
    4.      //. . . 操作数据
    5.     node=node.getNext();//获取下一个node
    6. }

    上述这样的方式,的确是可以遍历链表中的所有元素,但是却不是一个好的设计方式,因为我们把链表的基础数据结构Node直接暴露给用户了,普遍的做法就是利用迭代器(iterator)来实现链表的迭代功能。

    我们以上一节编写的SingleLinkList为例进行讲解,为其提供一个迭代所有元素的迭代器

    关于迭代器,Java中已经相关的接口定义java.util.Iterator,其定义了一个迭代器最基本要实现的功能,虽然实现这个接口不是必要的,但是这里打算实现这个接口

    1. public interface Iterator<E> {
    2.     /** 是否还有更多的元素可以迭代*/
    3.     boolean hasNext();
    4.     /** 返回下一个元素*/
    5.     E next();
    6.     /** 将迭代器当前迭代的元素,从链表中移除*/
    7.     void remove();
    8. }

    1、在SingleLinkList中定义一个内部类NodeIterator,实现Iterator接口

    1. private  class NodeIterator<T> implements Iterator<T>{
    2.     private Node node;
    3.     public NodeIterator(Node current) {
    4.         this.node = current;
    5.     }
    6.  
    7.     @Override
    8.     public boolean hasNext() {
    9.         return node!=null;
    10.     }
    11.  
    12.     @Override
    13.     public T next() {
    14.         Object data = node.getData();
    15.         node=node.getNext();
    16.         return (T)data ;
    17.     }
    18.  
    19.     @Override
    20.     public void remove() {
    21.         T t = (T) node.getData();
    22.         SingleLinkList.this.remove(t);
    23.     }
    24. }

    2、修改SingleLinkList,新增一个返回迭代器的方法

    关于返回迭代器方法的名称,是任意的,不过最好还是符合某种规范,java.lang.Iterable接口,定义了这样一个放回迭代器的方法

    1. public interface Iterable<T> {
    2.     Iterator<T> iterator();
    3. }

    其返回类型就是Iterator,现在你可能知道我们让NodeIterator实现Iterator接口的原因了,因为这样,我们就可以将自己写的迭代器通过Java的标准接口返回

    现在我们让SingleLinkList实现.Iterable接口,实现这个方法

    1. public class SingleLinkList<T> implements Iterable<T>{
    2. ...
    3.     @Override
    4.     public Iterator<T> iterator() {//可以看到,我们构建的时候,是把链表的第一个元素当做构造参数传递给了NodeIterator
    5.         return new NodeIterator<T>(firstNode);
    6.     }
    7. ...
    8. }

    现在所有的工作已经完成,剩下的就是测试了

    1. @Test
    2. public void testIterator(){
    3.     SingleLinkList<Integer> linkList=new SingleLinkList<Integer>();
    4.     for (int i = 0; i < 10; i++) {
    5.         linkList.addFirst(i);
    6.     }
    7.     System.out.println("链表中元素:");
    8.     linkList.display();
    9.     System.out.println(" 开始迭代:");
    10.     Iterator<Integer> iterator = linkList.iterator();
    11.     while (iterator.hasNext()){
    12.         Integer next = iterator.next();
    13.         System.out.println(next);
    14.     }
    15. }

    运行程序,输出:

    链表中元素:

    9    8    7    6    5    4    3    2    1    0   

    开始迭代:

    9

    8

    7

    6

    5

    4

    3

    2

    1

    0

    可以看到我们的迭代器已经正常工作

    特别的,由于我们的迭代器实现了Java的标准接口,所以我们可以使用java的增强for循环来进行迭代,如果没有实现这些接口,是无法使用增强for循环的

    1. @Test
    2. public void testIterator(){
    3.     SingleLinkList<Integer> linkList=new SingleLinkList<Integer>();
    4.     for (int i = 0; i < 10; i++) {
    5.         linkList.addFirst(i);
    6.     }
    7.     System.out.println("链表中元素:");
    8.     linkList.display();
    9.     System.out.println(" 开始迭代:");
    10.     //使用增强for循环进行迭代
    11.     for (Integer data : linkList) {
    12.         System.out.println(data);
    13.     }
    14. }
  • 相关阅读:
    t=20点击发送pingback
    Hibernate 序列生成主键
    oracle创建存储过程
    mysql允许某ip访问
    ORACLE用户解锁
    oracle查询锁表
    oracle杀掉执行的死循环存储过程
    oracle以逗号分隔查询结果列表
    查询oracle的session数
    oracle存储过程-获取错误信息
  • 原文地址:https://www.cnblogs.com/muzhongjiang/p/13672512.html
Copyright © 2011-2022 走看看