Java数据结构和算法-链表(5-迭代器)

来源:互联网 发布:张伯伦生涯场均数据 编辑:程序博客网 时间:2024/05/17 04:36

在链表中可以通过find()方法来查找到某一个特定的值,也可以通过delete方法删除某一个特定的值。这些操作都有一个搜索的工作,以找到特定的链接点。
在链表中进行一次某个值的查找删除或插入是简单的。但是现实中,经常会进行的是对某些特定的链接点的操作,而这些操作也都要进行搜索的工作。例如:要查找出所有某班成绩低于平均成绩的同学,要改变公司所有拥有最低工资的员工工资。这些都要进行搜索。
但是链表不是数组,链表没有下标,如果是数组的话,可以通过跟踪下标来确定当前搜索到的位置,当查找到第一个符合条件的值的同时,返回当前的下标,从而使得在继续查找下一个符合条件的值时,可以从该下标开始。链表不可以,链表在返回了符合条件的值后,必须从头开始查找下一个符合条件的值。如果有一个保存当前链接点的引用,在下一次查找时,从该引用的链接点进行步进,这样效率就会提高很多。
可能有人在说到“保存当前链接点的引用”时,就想到了在之前链表的介绍中,在链表类中定义的current,用current来存取一个链接点,然后使current递增,来移动到下一个链接点。
这种方法存在的一个问题是,只能进行一种引用。但是在现实中可能不止一个,就像经常要使用多个下标。并且需要引用的数目是未知的,所以这个引用不应该定义在链表内,而应该封装在一个独立的类中,并且这个类不能和链表相同。

迭代器

迭代器类是封装了对数据结构的数据项的引用的类,并用来遍历这些对象。在介绍的初始定义如下:

class ListIterator() {    private Link current;    //...}

它包含了一个对链接点的引用。
在产生链表后,可以通过调用某些方法来创建迭代器,比如下面的操作:

public static void main(String[] args) {    LinkList linkList = new LinkList();    ListIterator iter1 = linkList.getIterator();    Link link = iter1.getCurrent();    iter1.nextLink();}

在上面的代码中通过getIterator()来获取链表的迭代器,创建这个迭代器之后,可以通过它的递增,来指向下一个链接点。当然迭代器可以不止一个,迭代器总是指向链表中的一些链接点,它通过引用与链表相关联,但不等同于它就是链表或者链接点,如下图:
这里写图片描述

迭代器的其他特性

在链表章节的其他程序中,都会定义一个previous的字段,这使得链表进行删除或者插入操作时更加便捷,因此在迭代器中也封装了这个字段。
另外,在链表操作中我们可能会在表头进行一下操作,所以访问first也是必要的,但是first是链表的私有字段,迭代器要如何访问这个字段呢?
一种方式是在链表创建迭代器时,向迭代器传递一个对first的引用给迭代器,然后将这个引用存贮在迭代器的某个字段中。
还有一种方式是在链表中设一个公有方法getFirst来获取first的引用。不过这种方式有一个弊端是允许任何人修改first,这是危险的。

迭代器的方法

我们将链表中的部分方法也通过迭代器来实现,这样可以使得迭代器更加灵活和强大,例如迭代器包含以下的方法:

  • reset()–把迭代器设在表头
  • nextLink()–将迭代器移动到下一个链接点
  • getCurrent()–获取当前迭代器指向的链接点
  • insertAfter()–在迭代器指向的链接点之后插入
  • insertBefore()–在迭代器指向的链接点之前插入
  • atEnd()–判断迭代器是否在表尾
  • deleteCurrent()–删除当前迭代器指向的链接点

哪些任务由链表完成,哪些由迭代器完成,这并不好决定。insertFirst的插入位置是固定的不需要搜索所以将这个方法由链表来实现,而insertBefore这需要搜索工作,所以就有迭代器来实现。displayList可以通过链表也可以通过迭代器来实现,不过在下面的介绍中,我们通过链表实现。

迭代器的Java代码

class Link {    private int iData;    private Link next;    public Link(int d) {        iData = d;    }    public int getIData() {        return iData;    }    public void setIData(int d) {        iData = d;    }    public void displayLink() {        System.out.println("Link: " + iData);    }    //next的get和set方法}//end Linkclass LinkList {    private Link first;    public ListIterator getIterator() {        return new ListIterator(this);    }    public Link getFirst() {        return first;    }    public void setFirst(Link l) {        first = l;    }    public void insertFirst(int d) {        Link newLink = new Link(d);        newLink.next = first;        first = newLink;        }    public boolean isEmpty() {        return (first == null);    }    public void displayList() {        Link current = first;        while(current != null) {            current.displayLink();        }    }}//end LinkListclass ListIterator {    private Link previous;    private Link current;    private LinkList myList;    public ListIterator(LinkList ll) {        myList = ll;        reset();    }    public void reset() {        current = myList.getFirst();        previous = null;    }    public boolean atEnd() {        return (current.getNext() == null);    }    public void nextLink() {        if(atEnd()) {            reset();        } else {            previous = current;            current = current.getNext();        }    }    public void insertAfter(int d) {        Link newLink = new Link(d);        if(isEmpty()) {            myList.setFirst(newLink);            current = newLink;        } else {            newLink.setNext(current.getNext());            current.setNext(newLink);            nextLink();        }    }    public void insertBefore(int d) {        Link newLink = new Link(d);        if(previous == null) {            myList.setFirst(newLink);            reset();        } else {            newLink.setNext(current);            previous.setNext(newLink);            current = newLink;        }    }    public int deleteCurrent() {        Link temp = current;        if(previous == null) {            myList.setFirst(current.next);            reset();        } else {            previous.setNext(current.getNext());            if(atEnd())                reset();            else                current = current.getNext();        }        return temp.getIData();    }    public int getCurrent() {        return current.getIData();    }}//end ListIterator class IteratorApp {    public static void main(String[] args) {        LinkList linkList = new LinkList();        ListIterator ite = linkList.getIterator();        ite.insertAfter(21);        ite.insertAfter(14);        ite.insertAfert(45);        ite.insertAfter(30);        ite.insertAfter(67);        ite.reset();        if(ite.getCurrent()%3 == 0)            ite.deleteCurrent();        while(!ite.atEnd()) {            ite.nextLink();            if(ite.getCurrent()%3 == 0)                ite.deleteCurrent();        }        linkList.    }}

在上面的代码中,deleteCurrent方法当删除了当前所指向的链接点之后,current可能指向下一个,上一个或者回到表头,因为在删除链接点之后,迭代器仍指向附近的节点,能够便于下一个操作,而且如果指向上一个链接点,由于不是双向链表,链接点没有关于previous的引用,所以指向上一个链接点会比较复杂,因此deleteCurrent最后current会指向下一个链接点。

0 0
原创粉丝点击