1. 程式人生 > 實用技巧 >迭代器(iterator)

迭代器(iterator)

迭代器(iterator)

如果我們想遍歷陣列,這很容易,因為可以用陣列的下標跟蹤所在的位置,然而在連結串列中,節點沒有這樣的下標,怎樣才能提供給連結串列使用者類似於陣列下標的東西呢?這就是迭代器(iterator)的作用。

我們知道新增到連結串列中的資料(data),都會包裝成一個節點(node),節點之間通過引用儲存了先後關係(pre、next)。但是由於在獲取資料時(如getFirst),返回的直接是資料(data),資料本身沒有其之後資料的引用,因此無法遍歷。

但是node存在這樣的引用,如果我們直接把node返回給使用者,讓使用者自己從node獲取資料,不就可以實現遍歷了嗎?我們可以提供一個getFirstNode()方法,然後按照類似以下程式碼片段進行遍歷:

  1. Nodenode=linkedList.getFirstNode();
  2. while(node!=null){
  3. Objectdata=node.getData();
  4. //...操作資料
  5. node=node.getNext();//獲取下一個node
  6. }

上述這樣的方式,的確是可以遍歷連結串列中的所有元素,但是卻不是一個好的設計方式,因為我們把連結串列的基礎資料結構Node直接暴露給使用者了,普遍的做法就是利用迭代器(iterator)來實現連結串列的迭代功能。

我們以上一節編寫的SingleLinkList為例進行講解,為其提供一個迭代所有元素的迭代器

關於迭代器,Java中已經相關的介面定義java.util.Iterator

,其定義了一個迭代器最基本要實現的功能,雖然實現這個介面不是必要的,但是這裡打算實現這個介面

  1. publicinterfaceIterator<E>{
  2. /**是否還有更多的元素可以迭代*/
  3. booleanhasNext();
  4. /**返回下一個元素*/
  5. Enext();
  6. /**將迭代器當前迭代的元素,從連結串列中移除*/
  7. voidremove();
  8. }

1、在SingleLinkList中定義一個內部類NodeIterator,實現Iterator介面

  1. privateclassNodeIterator<T>implementsIterator<T>{
  2. privateNodenode;
  3. publicNodeIterator(Nodecurrent){
  4. this.node=current;
  5. }
  6. @Override
  7. publicbooleanhasNext(){
  8. returnnode!=null;
  9. }
  10. @Override
  11. publicTnext(){
  12. Objectdata=node.getData();
  13. node=node.getNext();
  14. return(T)data;
  15. }
  16. @Override
  17. publicvoidremove(){
  18. Tt=(T)node.getData();
  19. SingleLinkList.this.remove(t);
  20. }
  21. }

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

關於返回迭代器方法的名稱,是任意的,不過最好還是符合某種規範,java.lang.Iterable介面,定義了這樣一個放回迭代器的方法

  1. publicinterfaceIterable<T>{
  2. Iterator<T>iterator();
  3. }

其返回型別就是Iterator,現在你可能知道我們讓NodeIterator實現Iterator介面的原因了,因為這樣,我們就可以將自己寫的迭代器通過Java的標準介面返回

現在我們讓SingleLinkList實現.Iterable介面,實現這個方法

  1. publicclassSingleLinkList<T>implementsIterable<T>{
  2. ...
  3. @Override
  4. publicIterator<T>iterator(){//可以看到,我們構建的時候,是把連結串列的第一個元素當做構造引數傳遞給了NodeIterator
  5. returnnewNodeIterator<T>(firstNode);
  6. }
  7. ...
  8. }

現在所有的工作已經完成,剩下的就是測試了

  1. @Test
  2. publicvoidtestIterator(){
  3. SingleLinkList<Integer>linkList=newSingleLinkList<Integer>();
  4. for(inti=0;i<10;i++){
  5. linkList.addFirst(i);
  6. }
  7. System.out.println("連結串列中元素:");
  8. linkList.display();
  9. System.out.println("\n開始迭代:");
  10. Iterator<Integer>iterator=linkList.iterator();
  11. while(iterator.hasNext()){
  12. Integernext=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. publicvoidtestIterator(){
  3. SingleLinkList<Integer>linkList=newSingleLinkList<Integer>();
  4. for(inti=0;i<10;i++){
  5. linkList.addFirst(i);
  6. }
  7. System.out.println("連結串列中元素:");
  8. linkList.display();
  9. System.out.println("\n開始迭代:");
  10. //使用增強for迴圈進行迭代
  11. for(Integerdata:linkList){
  12. System.out.println(data);
  13. }
  14. }